自分で確認しないと納得しない人向け
確かめる結論
① SwiftのArrayは値型
② 配列自体を他の変数に代入した時には配列の内容のコピーが走らない
③ 配列の内容が変更された時に配列の内容がコピーされる
※②、③はいわゆるCopy-on-Write(CoW)のこと
確認方法
① SwiftのArrayは値型
var a = [1,2,3]
var b = a
b[1] = 0
とすると、bは[1,0,3]となるが、aは[1,2,3]のままなので値型である。
(もしも、参照型であればaも[1,0,3]となるので)
1> var a = [1,2,3]
a: [Int] = 3 values {
[0] = 1
[1] = 2
[2] = 3
}
2> var b = a
b: [Int] = 3 values {
[0] = 1
[1] = 2
[2] = 3
}
3> b[1] = 0
4> a
$R0: [Int] = 3 values {
[0] = 1
[1] = 2 // 元のaはそのまま
[2] = 3
}
5> b
$R1: [Int] = 3 values {
[0] = 1
[1] = 0 // bだけ変わった
[2] = 3
}
② 配列自体を他の変数に代入した時には配列の内容のコピーが走らない
配列を代入した段階ではa,b共に同じ値が格納されているので、実体が一つで十分であるから。
var a = [1,2,3]
var b = a
とすると、a,bともに0x00000001001004f0と同じメモリ番地を指しているため内容自体はコピーされていない。
1> var a = [1,2,3]
a: [Int] = 3 values {
[0] = 1
[1] = 2
[2] = 3
}
2> Unmanaged.passUnretained(a as AnyObject).toOpaque()
$R0: UnsafeMutableRawPointer = {
_rawValue = 0x00000001001004f0
}
3> var b = a
b: [Int] = 3 values {
[0] = 1
[1] = 2
[2] = 3
}
4> Unmanaged.passUnretained(a as AnyObject).toOpaque()
$R1: UnsafeMutableRawPointer = {
_rawValue = 0x00000001004000f0 // aと同じメモリの番地
}
③ 配列の内容が変更された時に配列の内容がコピーされる
上記②の続きで、
b[1] = 1
とした瞬間にコピーされる。
コピーされたことは変数bのアドレスが変更されていることによりわかる。
5> b[1] = 8
6> a
$R2: [Int] = 3 values {
[0] = 1
[1] = 2
[2] = 3
}
7> b
$R3: [Int] = 3 values {
[0] = 1
[1] = 8
[2] = 3
}
8> Unmanaged.passUnretained(a as AnyObject).toOpaque()
$R4: UnsafeMutableRawPointer = {
_rawValue = 0x00000001001004f0
}
9> Unmanaged.passUnretained(b as AnyObject).toOpaque()
$R6: UnsafeMutableRawPointer = {
_rawValue = 0x0000000100301400 // 違うメモリの番地を指している
}
補足
- 定数となるletは他の変数に代入してもそもそも内容をコピーする必要がなく例として面白くないのでvarのみを考えてる。
- コンパイラはApple Swift version 3.1 (swiftlang-802.0.53 clang-802.0.42)