Open2

Heart Of Swiftを理解する(第1章)

Shun UematsuShun Uematsu

概要

本スクラップはHeart Of Swiftの内容を自分自身が理解するために、文章にまとめたものを記述していきます。
そのため自分の理解が誤っている可能性があります。

Shun UematsuShun Uematsu

Value Semanticsとは

SwiftにおけるValue Semantics

SwiftにおけるValue Semanticsとは、インスタンスを初期化、代入、引数として渡すなどしても、元の値のコピーが作成され、そのコピーと元の値は独立して変更することができる。つまり、どちらを変更してももう一方に影響を与えない 性質を持つもののことを指しています。

Value Semantics

前述したようにValue Semanticsは、変更に対して他方に影響を与えない型です。
例えば以下のようなコードは自身以外に影響を与えません。

struct Foo {
  var value: Int = 0
}
var a = Foo()
var b = a
a.value = 2 // この時b.valueは`2`に変更されません。

理由としては、Fooは 値型 であるためです。
値型のインスタンス(より具体的に言うと、インスタンスを表すバイト列)は変数に直接格納されます。
そしてそのインスタンスを変数に代入した際、そのバイト列をコピーしてから変数に書き込まれます。
aとbは互いに変更に影響を与えないので、FooはValue Semanticsを持っていると言えます。

Reference Semantics

Value Semanticsの対比として、Reference Semanticsという性質もあります。
Reference Semanticsは変更が他方にも影響してしまうような性質を持つものを指しています。
例えば以下のようなコードは、変更が他方にも影響してしまいます。

class Foo {
  var value: Int = 0
}
var a = Foo()
var b = a
a.value = 2 // この時b.valueも`2`に変更されてしまいます。

理由としては、Fooは 参照型 であるためです。
値型と異なり参照型は、インスタンスを変数に代入してもバイト列は格納されません。
インスタンスを表すバイト列は別の領域に保存され、変数にはその保存領域を表すアドレス(e.g. 0x123DEF etc.)が保存されます。

Value Semanticsと値型 / Reference Semanticsと参照型はそれぞれイコールではない

注意しなければならないのは、値型ならValue Semanticsを持つ、参照型ならReference Semanticsを持つとは限りません。
値型でもValue Semanticsを持たない場合や、参照型でもValue Semanticsを持つ場合もあります。

値型でもValue Semanticsを持たない場合

class Bar {
  var value: Int = 0
}

struct Foo {
  var value: Int = 0
  var bar: Bar = Bar()
}

var a = Foo()
var b = a
a.value = 2
a.bar.value = 3 // この時b.bar.valueも変更されてしまう。

このようにFooは値型であるが、独立しておらず変更が他方にも影響してしまっています。
つまりFooはValue Semanticsを持たないと言えます。

参照型でもValue Semanticsを持つ場合

class Foo {
  let value: Int = 0
}
var a = Foo()
var b = a
a.value = 100 // これはコンパイルエラー

参照型はあるがvalueプロパティはイミュータブルであるので変更されることがなく、そのため他方に影響を与えることもありません。つまりFooはValue Semanticsを持つと言えます。

ただしイミュータビリティ を持つ場合は Value Semanticsに加えてReference Semantics持つみたいです。
また以下の場合も同様

struct Foo {
    let value: Int = 0
}

また先程の値型でもValue Semanticsを持たない場合の例のBarを以下のように書き換えると、

class Bar {
  let value: Int = 0
}

struct Foo {
  var value: Int = 0
  var bar: Bar = Bar()
}

var a = Foo()
var b = a
a.value = 2
a.bar.value = 3 // コンパイルエラー

a.bar.valueは書き換えることはできないので、他方に影響を与える可能性がなくなります。
よってこの場合、FooはValue Semanticsを持つと言えます。

Value SemanticsかReference Semanticsかの判断

ここまで値型だが参照型のミュータブルなプロパティを持っていればValue Semanticsを持たない、という例がありましたが、「値型だが参照型のミュータブルなプロパティを持っていればValue Semanticsを持たない」とパターンで判断するのは危険です。
値型だが参照型のミュータブルなプロパティを持っていても、Copy-on-Writeなどの仕組みを使ってValue Semanticsを持つ場合もあるみたいです。(Arrayなど)
Value Semanticsを持つかどうかは、定義に基づいているかどうかで判断することが重要です。