值类型 VS 引用类型
值类型和引用类型的核心不同就是数据和数据的存储位置。我们用局部变量、参数、属性和全局变量来存储数据。存储数据有两种最基本的方式。
对于值语义,数据是直接保存在变量中。对于引用语义,数据保存在其他地方,变量存储的是该数据的引用地址。当我们访问数据时,这种差异不一定很明显。但是拷贝数据时就完全不一样了。对于值语义,你得到的是该数据的拷贝。对于引用语义,你得到的是该数据的引用地址拷贝。
由于许多语言的核心是“一切皆对象”,number 其实是用引用类型来实现的。然而,它们是不可变引用类型,不可变引用类型和值类型的差异是很难察觉的。它们的行为和值类型一样,即使它们不是以这种方式实现。
这是理解值类型和引用类型的重要部分。就语言语义方面,区别是很重要的。当修改数据时,如果你的数据是不可变的,那么值类型/引用类型之间的区别就消失了,或者至少变成纯粹的性能问题而不是语义问题。
Objective-C 中也有类似的东西,就是标记指针(tagged pointers)。标记指针把对象直接存储在指针值中,因此它实际上是值类型,拷贝指针相当于拷贝对象。Objective-C 的库只会把不可变类型存储到标记指针中,所以使用的时候感受不到区别。有些 NSNumber 是引用类型,有些是值类型,但是使用上没有区别。
这两者之间的根本区别在于,当你使用 = 时会发生什么。值类型会得到该对象的副本,引用类型仅仅得到该对象的引用。
因此,决定使用哪一个的基本问题是:是否需要拷贝?是否需要经常拷贝?
Swift 是可拷贝的。这意味着 Array、Dictionary 和 String 是结构体而不是类。可以将他们的拷贝作为参数来使用
嵌套类型
嵌套值类型和引用类型有四种方式。哪怕只用到了其中一种,你的生活都会变得更加有趣。
包含其他引用类型的引用类型,这没什么特别的。如果持有内部或外部值的引用,就可以修改这个值。改动会同步到所有持有者。
包含其他值类型的值类型,这样做的结果是一个更庞大的值类型。当内部值是外部值的一部分时,如果你将外部值存储到某个新地方,整个值类型都会被拷贝,包括内部值。如果你将内部值储存到新地方,那就只拷贝内部值。
包含值类型的引用类型,被引用的值会变大。外部值的引用可以操作整个对象,包括内部值。修改内部值时,外部值引用的持有者都会同步改动。如果你将内部值储存到新地方,它会被拷贝。
包含引用类型的值类型,这就有点复杂了。你可能会遇到意料之外的行为。这有利有弊,取决于你的使用方式。如果你将一个引用类型放到值类型中,然后拷贝这个值类型到一个新地方,拷贝中的内部对象的引用值是相同的,它们都指向相同的地方。












网友评论