1. 程式人生 > >Swift學習筆記(12)--陣列和字典的複製

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的了。