Swiftの構造体(struct)はデフォルトで値型であり、構造体のインスタンスをコピーする際には独立したコピーが作成されます。しかし、クラスとは異なり、構造体のメソッドはコンパイラーからの明示的な許可なしにselfやそのプロパティを変更することができません。CやC++の初期のバージョンでは、構造体は常に変更可能であったため、予期しない副作用が発生していました。Swiftは安全性を高めるために、構造体の状態を変更するメソッドにmutatingキーワードを明示的に付けることを要求しています。
問題は、構造体のプロパティを変更する必要があるメソッドが通常のメソッドとして宣言されている場合、コンパイラーがそれを許可しないということです。mutatingがないとselfやそのプロパティを変更することができません。
解決策は、mutatingキーワードを使用してそのようなメソッドを宣言することです。これにより、コンパイラーにselfやその内部プロパティの変更を許可するシグナルを送ります。
コード例:
struct Counter { var value = 0 mutating func increment() { value += 1 } // このメソッドはmutatingを外すとコンパイルされません } var counter = Counter() counter.increment() // valueは1になりました
重要な特徴:
1. letで宣言された構造体でmutatingメソッドを呼び出すことはできますか?
いいえ、できません。定数let値の構造体はmutatingメソッドであっても変更することができません。
let counter = Counter() counter.increment() // コンパイルエラー
2. 構造体内のクラスの内部プロパティはmutatingメソッド内で変更できますか?
はい、構造体のプロパティが参照型(例えば、クラス)であれば、その内部プロパティはmutatingなしで変更できますが、構造体全体はmutatingを介してのみ変更できます。
class State { var value = 0 } struct Wrapper { var state = State() mutating func change() { state.value += 1 } }
3. mutatingなしでメソッド内でcomputed propertyを変更することはできますか?
いいえ、computed propertyにsetがある場合、その値をメソッド内で変更することもmutatingを必要とします。
プロジェクトで単純なカウンタを構造体で実装しましたが、開発者はメソッドをmutatingとしてマークし忘れました。値が変更されないため、テストが通りません。
利点:
欠点:
構造体のメソッドはmutatingとしてマークされ、テストが通り、変更が正しく更新されます。コードはチームの全メンバーに理解されます。
利点:
欠点: