Swift-值类型与引用类型

Swift-值类型与引用类型

Swift类型有两个类别,第一为值类型,每个实例中各保存唯一的副本,通常被定义成struct、enum或tuple,第二为引用类型,每个实例共享一个单一的副本,通常被定义成像类别(class),在这篇文章我们要来讨论值类型与引用类型以及如何在它们之间选择。

值类型

值类型的最基本的特点是复制,它分配、初始化、参数传递,建立一个与自已独立的副本,例如:

struct S { var data: Int = 1 }
var a = S()
var b = a
a.data = 20
println("\(a.data), \(b.data)")

输出结果:

20, 1

引用类型

复制引用,另一方面,隐式的建立一个共享实例,复制后,两个变数都参考同一个单一实例,以便修改第二个数值时也能原来的同步,例如:

// Reference type example
class C { var data: Int = 1 }
var x = C()
var y = x
x.data = 20
println("\(x.data), \(y.data)")

输出结果:

20, 20

两种的安全性

有一个主要的理由解释选择值类型胜过引用类型就是能更容易的理解你写的程式。如果你总是得到独特、复制的实例,你可以相信没有在程式其他地方可以变更你的资料,这种情形在多线程的环境中非常有帮助,像其他线程可以在其他情况改变你的资料时,这可能会引其其他的错误,也会令你很难去除错。

由于这两种类型被定义当你改变资料时是不同的处理方式,不过有一种特例值类型与引用类型功能是相似的,那就是当你的实例不写入资料只读资料时,值类型与引用类型的功能就是相同的。

你可能会想那是有价值的,如果一个情况class是不可变的。它能使你更容易去使用NSObject物件维护并保持原来的语义。现在,你可以在Swift中写一个不可变的类别并籍著使用不可变的存储属性避免暴露任何可以修改状态的API。事实上,很多Cocoa类别,像NSURL被设计成不可变类别。然而,Swift并没有提供任何语言的机制去施行类别像struct、enum一样成为不可变(像子类别)。

两种适用的用途

所以,如果你想建立一个新的类型,你怎么决定要哪一种?当你使用Cocoa,许多API预计都是NSObject的子类,所以你必须使用一个类。对于其他情况,这里有一些建议:

使用值类型

  • 比较实例的资料内容
  • 你想要拷贝成独立的状态
  • 你的资料被使用在多个线程中

使用引用类型

  • 比较实例是否引用同一个类
  • 你想要建立一个共享可变的状态

结语:

在Swift中,阵列、字串、字典都是值类型,它们有着类似C的int,资料都有一个独立的实例,你不需要做任何特别的事,像是做一个明确的拷贝副本、程式在你背后随意的变更资料,你都能安全的在多线程更改资料,不需要去对资料做同步,这在你写程式时都很有帮助。

参考资讯

Value and Reference Types