続き
参照型で起こる副作用を 値型で防止する
- 意図しない変更
- 整合性の破壊
Swiftは 上記に対する 対処を値型で行う。
struct Person {
var name: String
}
var person1 = Person(name: "Alice")
var person2 = person1
person2.name = "Bob"
print(person1.name) // Alice
Kotlinは 防御的コピー + イミュータブルクラス
data class Person(val name: String)
val person1 = Person(name = "Alice")
val person2 = person1.copy(name = "Bob")
println(person1.name) // Alice
防御的コピーと比べると 、いちいち全部作り直す手間がない分パフォーマンスが良い
さらに、Swiftの値型は、「複数の参照が同じデータを共有する場合、データはコピーされずにそのまま使用する。しかし、いずれかの参照がデータを変更しようとすると、その時点でコピーが作成され、変更はコピーに対して行われる。」 といった Copy on Write と呼ばれる仕組みがあって、配列のような大きくなりうるデータ に対する操作も パフォーマンスをよくしている。
var array1 = [1, 2, 3]
var array2 = array1 // 共有される
array2.append(4) // この時点でコピーが作成される
print(array1) // [1, 2, 3]
print(array2) // [1, 2, 3, 4]
値型の変更を 参照型っぽくやる
inout 引数 を使うと もとの値型を変更することができる。が、Value Semanticsは壊れる可能性がある。
func modifyArray(_ array: inout [Int]) {
array.append(4)
}
var array1 = [1, 2, 3]
modifyArray(&array1)
print(array1) // [1, 2, 3, 4]
メソッドの場合は mutating で inout と同じことができる
struct Person {
var name: String
mutating func changeName(to newName: String) {
name = newName
}
}
var person = Person(name: "Alice")
person.changeName(to: "Bob")
print(person.name) // Bob