読者です 読者をやめる 読者になる 読者になる

読み書きプログラミング

日常のプログラミングで気づいたことを綴っています

cloneメソッド

最近、Swiftを始めました。Swiftはいいとこ取りの言語で、どこかで見た良さげな言語仕様が採用されているので書きやすいです。
でも、インスタンスをコピーするcloneメソッドで苦労しました。

事実上finalのクラスに単にcloneメソッドを実装する分には何の問題もないのですが、スーパークラスになることを前提に、しかもインスタンス変数を増やさないサブクラスでも動作するようなcloneメソッドの定義は大変でした。

以下が苦労した結果の集大成です。

class SuperClass {
    var value: SomeValueType // for simplicity of sample

    init() {
        self.value = SomeValueType()
    }
    
    required init(clone: SuperClass) {
        self.value = clone.value
    }

    func clone() -> Self {
        return self.dynamicType.init(clone: self)
    }
}

インスタンス変数はValue Typeとしました。もしReference Typeを使いたいなら、init(clone:)がReference Typeのcloneを使うように変更する必要があるでしょう。

重要なポイントは以下の2点です。
#コピーの実装部分にinitを使うこと
#コピーコンストラクタにrequiredをつけること
#cloneメソッドの戻り値の型にSelfを指定すること

これで、インスタンス変数を増やさないサブクラスは、何もしなくてもcloneメソッドが使えます。
インスタンス変数を増やした場合には、もちろん、init(clone:)をoverrideしてください。(overrideというキーワードは使わず、requiredでオーバーライドします)

cloneをcomputed propertyにしたかったのですが、Swift 2では型としてSelfを指定できるのは戻り値だけなのでできないようです。