1. ホーム
  2. swift

[解決済み] 自己を返すプロトコルfunc

2023-05-13 11:18:16

質問

オブジェクトのコピーを返すプロトコルPがあります。

protocol P {
    func copy() -> Self
}

と、Pを実装したクラスCがあります。

class C : P {
    func copy() -> Self {
        return C()
    }
}

しかし、戻り値を Self というエラーが出ます。

型 'C' の return 式を型 'Self' の return 式に変換することができません。

また C .

class C : P {
    func copy() -> C  {
        return C()
    }
}

その結果、以下のようなエラーが発生しました。

非終端クラス 'C' のメソッド 'copy()' は、必ず Self に適合するように を返さなければなりません。

をプレフィックスとする場合を除き、何も動作しません。 class Cfinal を行う。

final class C : P {
    func copy() -> C  {
        return C()
    }
}

しかし、もし私がCをサブクラス化したいのであれば、何も動作しません。これを回避する方法はありますか?

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

問題は、コンパイラが守ると証明できない約束をしていることです。

そこであなたはこの約束を作りました:呼び出し copy() を呼び出すと、完全に初期化されたそれ自身の型が返されます。

しかし、その後、あなたが実装した copy() をこのように実装しました。

func copy() -> Self {
    return C()
}

これで、オーバーライドしないサブクラスである copy() . そして、私は C を返しますが、完全に初期化された Self (約束した)ではないのです。だから、それはダメなんだ。どうでしょう。

func copy() -> Self {
    return Self()
}

さて、これではコンパイルできませんが、たとえできたとしても、それは意味がありません。そのサブクラスはつまらないコンストラクタを持たないかもしれませんので D() は合法ではないかもしれません。(以下を参照してください)。

OK、ではどうでしょう。

func copy() -> C {
    return C()
}

はい、でもこれでは Self . それは C . まだ約束を守ってないのか。

しかし、ObjCはそれができるのです!" まあ、そんなところです。ほとんどの場合、Swiftがそうであるように、あなたが約束を守るかどうかを気にしないためです。もし、あなたが copyWithZone: をサブクラスで実装することに失敗した場合、オブジェクトを完全に初期化することに失敗する可能性があります。コンパイラは、それを行ったことを警告することさえしません。

"しかし、ObjCのほとんどのものはSwiftに翻訳することができ、ObjCには NSCopying ."そうです、そしてこれがどのように定義されているかです。

func copy() -> AnyObject!

ということで、同じようにできます(ここでは「!」の理由はありません)。

protocol Copyable {
  func copy() -> AnyObject
}

That says "I'm not promising anything about what you get back."とも言えるでしょう。

protocol Copyable {
  func copy() -> Copyable
}

それは、あなたができる約束です。

しかし、C++について少し考えて、私たちができる約束があることを思い出してください。 ができます。 を作ることができます。私たちは、私たちとすべてのサブクラスが特定の種類のイニシャライザーを実装することを約束することができ、Swiftはそれを強制します(そして、私たちが真実を語っていることを証明することができます)。

protocol Copyable {
  init(copy: Self)
}

class C : Copyable {
  required init(copy: C) {
    // Perform your copying here.
  }
}

といった具合に、コピーを実行します。

これをもう一歩進めると dynamicType を使用します。そして、それが常に私たちが望むものであることを確認するために広範囲にテストしたわけではありませんが、それは正しいはずです。

protocol Copyable {
  func copy() -> Self
  init(copy: Self)
}

class C : Copyable {
  func copy() -> Self {
    return self.dynamicType(copy: self)
  }

  required init(copy: C) {
    // Perform your copying here.
  }
}

ここでは、コピーを実行するイニシャライザがあることを約束し、実行時にどれを呼び出すかを決定し、あなたが探していたメソッド構文を与えてくれます。