1. ホーム
  2. struct

[解決済み] 構造体の高速化と変異

2022-05-18 05:03:15

質問

Swiftで値の型を変更するとき、完全に理解していないことがあります。

iBookの"The Swift Programming Language"に書いてある通りです。 デフォルトでは、値型のプロパティはそのインスタンスメソッド内から変更することはできません。

そして、これを可能にするために、メソッドを宣言する際に mutating キーワードでメソッドを宣言することができます。

全くもって意味不明なのがこれ。 構造体の外側から変数を変更することはできますが、構造体自身のメソッドから変数を変更することはできません。オブジェクト指向言語では、一般的に変数をカプセル化して、内部からのみ変更できるようにするため、これは直感に反しているように思えます。構造体の場合、これは逆になっているように見えます。詳しく説明するために、次のようなコード スニペットを示します。

struct Point {
    var x = 0, y = 0
    mutating func moveToX(x: Int, andY y:Int) { //Needs to be a mutating method in order to work
        self.x = x
        self.y = y
    }
}

var p = Point(x: 1, y: 2)
p.x = 3 //Works from outside the struct!
p.moveToX(5, andY: 5) 

構造体の中身は簡単に変更できるのに、構造体の中身は自分のコンテキストの中から変更できない理由を知っている人はいますか?

どのように解決するのですか?

mutability属性は、型ではなく、ストレージ(定数や変数)に付けられます。構造体には2つのモードがあると考えることができます。 ミュータブル 不変 . 構造体の値をイミュータブルストレージに代入する場合(ここでは let または 定数 を使用すると、値はイミュータブルモードになり、値の状態を変更することはできません。(ミューティングメソッドの呼び出しを含む)

値がミュータブルストレージに割り当てられている場合(ここでは var または 変数 Swiftでは変数)、それらの状態を自由に変更することができ、mutatingメソッドの呼び出しも許可されます。

また、クラスにはこのimmutable/mutableモードがありません。これはクラスが通常 参照可能な エンティティを表現するために使われるからです。そして、参照可能なエンティティは通常変更可能です。なぜなら、適切なパフォーマンスでエンティティの参照グラフを不変の方法で作成し管理することは非常に難しいからです。彼らはこの機能を後で追加するかもしれませんが、少なくとも今はありません。

Objective-C のプログラマにとって、mutable/immutable のコンセプトは非常になじみ深いものです。Objective-C では、それぞれの概念に対して 2 つの分離したクラスがありましたが、Swift では、1 つの構造体でこれを行うことができます。半分仕事です。

C/C++プログラマにとっては、これも非常に馴染みのある概念です。これはまさに const キーワードはC/C++で行うものです。

また、イミュータブルな値は非常にうまく最適化することができます。理論的には、Swift コンパイラ(または LLVM)は、immutable キーワードで渡された値に対してコピーエリシジョンを実行することができます。 let で渡された値に対して、C++のようにコピーエリジョンを実行できます。もしあなたがimmutable構造体を賢く使うなら、それはrefcountedクラスを凌駕することでしょう。

アップデート

Joseph が主張するように、これでは なぜ を提供していないと主張したので、もう少し追加しています。

構造体には2種類のメソッドがあります。 プレーン ミューティング メソッドを使用します。 プレーン メソッドが意味するのは 不変(または変異しない) . この分離は イミュータブル セマンティクスをサポートするためにのみ存在します。immutable モードのオブジェクトは、その状態を全く変更してはいけません。

そうすると、イミュータブルメソッドはこのことを保証しなければなりません。 意味での不変性 . つまり、内部の値を一切変更してはいけないということです。つまり、コンパイラは不変のメソッドではそれ自身の状態を一切変更しないようにする。これに対して、mutatingメソッドは状態を自由に変更することができます。

そして、次のような疑問があるかもしれません。 なぜimmutableがデフォルトなのか? それは、変化する値の将来の状態を予測するのが非常に難しいからで、通常はそれが頭痛やバグの主な原因となります。多くの人が、解決策は変異しやすいものを避けることだと同意し、そして デフォルトで不変 は、C/C++ 系の言語とその派生言語において、何十年にもわたって希望リストの上位に挙げられていました。

参照 純然たる機能的スタイル をご覧ください。いずれにせよ、不変のものにはいくつかの弱点があるため、私たちは依然として不変のものを必要としており、それについて議論することは話題から外れているように思えます。

お役に立てれば幸いです。