SwiftではDictionary型とArray型で参照渡しなのか値渡しなのか混乱しやすそうな部分がある。
Dictionary
Swiftの場合、多くの言語と同じようにClassやObjectが参照渡しでStructやInt,Stringなどは値がコピーされる。DictionaryはStructとして内部では実装されているらしいので値渡しとなる。例えば以下のコード
var ages = ["Peter": 23, "Wei": 35, "Anish": 65, "Katya": 19]
var copiedAges = ages
Dictionaryを他の変数に代入している。ここでDictionaryは値渡しでコピーされるのでcopiedAges
とages
は別物。
copiedAges["Peter"] = 24
println(ages["Peter"])
// prints "23"
実際copiedAges
に変更を加えてもagesには影響がない。
Array
Arrayの場合は話がもう少し複雑。ArrayもDictionaryと同じようにStructで実装されているので基本的には値渡しかと思いきや、こちらは参照が渡されてしまう。
var a = [1, 2, 3]
var b = a
var c = a
a[0] = 42
println(a[0])
// 42
println(b[0])
// 42
println(c[0])
// 42
何故かb
やc
まで変わっている。なるほどArrayの場合は参照渡しになっているのねと思いきや、そうならない場合もある。実はArrayの長さを変更するような操作を行う場合には新しいArrayが作られてしまう。
a.append(4) // <- ここで長さが変わる
a[0] = 777
println(a[0]) // <- そうするとaには新しいArrayが入るみたい
// 777
println(b[0])
// 42
println(c[0])
// 42
というわけでaの参照する先とb,cが参照する先は異なるようになるので値が変更されないことになる。
基本的にはArrayは参照渡しになってしまう。
参照を渡したくない
勝手に他の変数を通じてArrayが書き換えられるのはあまり気分のいいものではない。そこでArrayの代入を行っても別の参照を持ってくれるようにする方法がある。
b.unshare()
b[0] = 100
println(b[0])
// 100
println(c[0])
// 42
unshare
を呼ぶと、bにはcと異なるArrayを持ってくれることになる。
でも個人的にはcopy
を使う方がわかりやすい。
var b = a.copy()
とやっておくとbにはaのコピーが入る。