Swift学习笔记,12--数组和字典的复制

Swift中,数组Array和字典Dictionary是用结构来实现的,但是数组与字典和其它结构在进行赋值或者作为参数传递给函数的时候有一些不同。

并且数组和字典的这些操作,又与Foundation中的NSArray和NSDictionary不同,它们是用类来实现的。

注意:下面的小节将会介绍数组,字典,字符串等的复制操作。这些复制操作看起来都已经发生,但是Swift只会在确实需要复制的时候才会完整复制,从而达到最优的性能。

字典的赋值和复制操作

每次将一个字典Dictionary类型赋值给一个常量或者变量,或者作为参数传递给函数时,字典会在赋值或者函数调用时才会被复制。这个过程在上面的小节:结构和枚举是数值类型中描述了。

如果字典中的键值是数值类型(结构或者枚举),它们在赋值的时候会同时被复制。相反,如果是引用类型(类或者函数),引用本身将会被复制,而不是类实例或者函数本身。字典的这种复制方式和结构相同。

下面的例子演示的是一个叫ages的字典,存储了一些人名和年龄的对应关系,当赋值给copiedAges的时候,里面的数值同时被完整复制。当改变复制了的数值的时候,原有的数值不会变化,如下例子:

var ages = ["Peter": 23, "Wei": 35, "Anish": 65, "Katya": 19] var copiedAges = ages

这个字典的键是字符串String类型,值是Int类型,都是数值类型,那么在赋值的时候都会被完整复制。

copiedAges["Peter"] = 24 println(ages["Peter"]) // prints "23"

数组的赋值和复制操作

和字典Dictionary类型比起来,数组Array的赋值和复制操作就更加复杂。Array类型和C语言中的类似,仅仅只会在需要的时候才会完整复制数组的值。

如果将一个数组赋值给一个常量或者变量,或者作为一个参数传递给函数,复制在赋值和函数调用的时候并不会发生。这两个数组将会共享一个元素序列,如果你修改了其中一个,另外一个也将会改变。

对于数组来说,复制只会在你进行了一个可能会修改数组长度操作时才会发生。包括拼接,添加或者移除元素等等。当复制实际发生的时候,才会像字典的赋值和复制操作一样。

下面的例子演示了数组的赋值操作:

var a = [1, 2, 3] var b = a var c = a

数组a被赋值给了b和c,然后输出相同的下标会发现:

println(a[0]) // 1 println(b[0]) // 1 println(c[0]) // 1

如果改变a中的某个值,会发现b和c中的数值也会跟着改变,因为赋值操作没有改变数组的长度:

a[0] = 42 println(a[0]) // 42 println(b[0]) // 42 println(c[0]) // 42

但是,如果在a中添加一个新的元素,那么就改变了数组的长度,这个时候就会发生实际的复制操作。如果再改变a中元素的值,b和c中的元素将不会发生改变:

a.append(4) a[0] = 777 println(a[0]) // 777 println(b[0]) // 42 println(c[0]) // 42

设置数组是唯一的

如果可以在对数组进行修改前,将它设置为唯一的就最好了。我们可以通过使用unshare方法来将数组自行拷贝出来,成为一个唯一的实体。

如果多个变量引用了同一个数组,可以使用unshare方法来完成一次“独立”

b.unshare()

这时候如果再修改b的值,c的值也不会再受影响

b[0] = -105 println(a[0]) // 777 println(b[0]) // -105 println(c[0]) // 42

检查两个数组时候共用了相同的元素

使用实例相等操作符来判断两个数组是否共用了元素(===和!===)

下面这个例子演示的就是判断是否共用元素:

if b === c {     println("b and c still share the same array elements.") } else {     println("b and c now refer to two independent sets of array elements.") } // prints "b and c now refer to two independent sets of array elements."

也可以使用这个操作来判断两个子数组是否有共用的元素:

if b[0...1] === b[0...1] {     println("These two subarrays share the same elements.") } else {     println("These two subarrays do not share the same elements.") } // prints "These two subarrays share the same elements."

强制数组拷贝

通过调用数组的copy方法来完成强制拷贝。这个方法将会完整复制一个数组到新的数组中。

下面的例子中这个叫names的数组会被完整拷贝到copiedNames中去。

var names = ["Mohsen", "Hilary", "Justyn", "Amy", "Rich", "Graham", "Vic"] var copiedNames = names.copy()

通过改变copiedNames的值可以验证,数组已经被完整拷贝,不会影响到之前的数组:

copiedNames[0] = "Mo" println(names[0]) // prints "Mohsen"

注意:如果你不确定你需要的数组是否是独立的,那么仅仅使用unshare就可以了。而copy方法不管当前是不是独立的,都会完整拷贝一次,哪怕这个数组已经是unshare的了。