swift类型分为值类型和引用类型,最典型的对照是结构体和类。
定义一个结构体:
struct PointStruct {
var x: Int
var y: Int
}
现在让我们来看看下⾯的代码⽚段:
var structPoint = PointStruct(x: 1, y: 2)
var sameStructPoint = structPoint
sameStructPoint.x = 3
在执⾏这段代码之后,很明显 sameStructPoint 等于 (x: 3, y: 2)。然⽽ structPoint 仍然保持
原始值。
关键区别在于:当被赋以⼀个新值或是作为参数传递给函数时,值类型会被复制。之所以给 sameStructPoint.x 赋值并不更新原来的 structPoint,正是因为先前的 sameStructPoint = structPoint 赋值过程中,发⽣了值复制。
为了进⼀步说明区别,我们可以声明⼀个点类:
class PointClass {
var x: Int
var y: Int
init(x: Int, y: Int ) {
self.x = x
self.y = y
}
}
然后修改上⾯的代码⽚段,使⽤类代替结构体:
var classPoint = PointClass(x: 1, y: 2)
var sameClassPoint = classPoint
sameClassPoint.x = 3
现在,给 sameClassPoint.x 赋值之后,既修改了 sameClassPoint,也修改了 classPoint,原因在于类是引⽤类型。理解值类型与引⽤类型之间的区别极其重要 —— 由此你可以预测赋值⾏为将会如何修改数据,同时哪些代码可能受到这个改变的影响。
Swift ⼏乎所有类型都是值类型,包括数组,字典,数值,布尔值,元组和枚举 。只有类 (class) 是⼀个例外。这正说明了 Swift 正在从 “⾯向对象编程” 进化到其他的编程范式。
⼤多 Objective-C 程序员对于可变性和不可变性的概念很熟悉。Apple 的 CoreFoundation 和 Foundation 框架提供的许多数据结构都存在不可变和可变两个版本,⽐如NSArray 和 NSMutableArray等。⼤多数情况下使⽤不可变类型是默认选项,就像 Swift 中⽐起引⽤类型更倾向于优先选择值类型⼀样。不过,相较于 Swift,Objective-C 中并没有万⽆⼀失的⽅法来确保变量不可变。我们可以将对象的属性声明为只读 (或者为了避免可变,仅暴露⼀个接⼝),但这⽆法阻⽌我们 (⽆意地) 在类型内部修改已经被初始化的值。
⽐⽅说,当遇上遗留代码时,那些编译器⼒所不逮的可变性假定实在是太容易被打破了。在使⽤可变变量时,如果没有经由编译器进⾏检验,保证任何⼀种规范都将是天⽅夜谭。在和框架代码打交道的时候,我们通常可以将已经存在的可变类封装到⼀个结构体中。不过,这⾥务必⼩⼼:如果我们在结构体中保存了⼀个对象,引⽤是不可变的,但是对象本⾝却可以改变。Swift 数组就是这样的:它们使⽤低层级的可变数据结构,但提供⼀个⾼效且不可变的接⼝,这被称为写⼊时复制 (copy-on-write) 的技术。
网友评论