值类型是这样一种类型,当它被赋值给一个变量、常量或者被传递给一个函数的时候,其值会被拷贝。
在之前的章节中,你已经大量使用了值类型。实际上,Swift 中所有的基本类型:整数(integer)、浮点数(floating-point number)、布尔值(boolean)、字符串(string)、数组(array)和字典(dictionary),都是值类型,其底层也是使用结构体实现的。
Swift 中所有的结构体和枚举类型都是值类型。这意味着它们的实例,以及实例中所包含的任何值类型的属性,在代码中传递的时候都会被复制。
注意
标准库定义的集合,例如数组,字典和字符串,都对复制进行了优化以降低性能成本。新集合不会立即复制,而是跟原集合共享同一份内存,共享同样的元素。在集合的某个副本要被修改前,才会复制它的元素。而你在代码中看起来就像是立即发生了复制。
请看下面这个示例,其使用了上一个示例中的 Resolution
结构体:
let hd = Resolution(width: 1920, height: 1080)
var cinema = hd
在以上示例中,声明了一个名为 hd
的常量,其值为一个初始化为全高清视频分辨率(1920
像素宽,1080
像素高)的 Resolution
实例。
然后示例中又声明了一个名为 cinema
的变量,并将 hd
赋值给它。因为 Resolution
是一个结构体,所以会先创建一个现有实例的副本,然后将副本赋值给 cinema
。尽管 hd
和 cinema
有着相同的宽(width)和高(height),但是在幕后它们是两个完全不同的实例。
下面,为了符合数码影院放映的需求(2048
像素宽,1080
像素高),cinema
的 width
属性被修改为稍微宽一点的 2K 标准:
cinema.width = 2048
查看 cinema
的 width
属性,它的值确实改为了 2048
:
print("cinema is now \(cinema.width) pixels wide")
// 打印 "cinema is now 2048 pixels wide"
然而,初始的 hd
实例中 width
属性还是 1920
:
print("hd is still \(hd.width) pixels wide")
// 打印 "hd is still 1920 pixels wide"
将 hd
赋值给 cinema
时,hd
中所存储的值会拷贝到新的 cinema
实例中。结果就是两个完全独立的实例包含了相同的数值。由于两者相互独立,因此将 cinema
的 width
修改为 2048
并不会影响 hd
中的 width
的值,如下图所示:
枚举也遵循相同的行为准则:
enum CompassPoint {
case north, south, east, west
mutating func turnNorth() {
self = .north
}
}
var currentDirection = CompassPoint.west
let rememberedDirection = currentDirection
currentDirection.turnNorth()
print("The current direction is \(currentDirection)")
print("The remembered direction is \(rememberedDirection)")
// 打印 "The current direction is north"
// 打印 "The remembered direction is west"
当 rememberedDirection
被赋予了 currentDirection
的值,实际上它被赋予的是值的一个拷贝。赋值过程结束后再修改 currentDirection
的值并不影响 rememberedDirection
所储存的原始值的拷贝。