2015-10-07 8 views
5

エラー:それは、非パラメーターで「自己」を使用しているため、プロトコルのプロトコルの要件「インスタンス」は、非結果型位置共変のセルフを返すプロトコルメソッドをどのように実装しますか?

protocol Protocol { 
    var instance: Self {get} 
} 

class Class: Protocol { 
    var instance: Class {return Subclass()} 
} 

class Subclass: Class {} 
を非最終クラス(「クラス」)によって満たすことができません

ここでは、私が望むものをC#で表現する方法を示します。 (C#は、私の知る限り、ジェネリックパラメータ "Self"は実際にSwiftから知っているSelfであることを強制する方法はありませんが、適切なことをするためのドキュメントとして十分機能します)

どのようにそれはスウィフトの将来のバージョンで見えるかもしれません
interface Protocol<Self> where Self: Protocol<Self> { 
    Self instance {get;} 
} 

class Class: Protocol<Class> { 
    public Class instance {get {return new Subclass();}} 
} 

class Subclass: Class {} 

...:私は私の問題に関連していることの一部をエミュレートしていますどのように

protocol Protocol { 
    typealias FinalSelf: Protocol where FinalSelf.FinalSelf == FinalSelf 

    var instance: FinalSelf {get} 
} 

class Class: Protocol { 
    var instance: Class {return Subclass()} 
} 

class Subclass: Class {} 

protocol Protocol: ProtocolInstance { 
    static var instance: ProtocolInstance {get} 
} 

protocol ProtocolInstance {} 


class Class: Protocol { 
    static var instance: ProtocolInstance {return Subclass()} 
} 

class Subclass: Class {} 

そして、ここでは、私は私のコードの関連部分であると信じるものです:

protocol Protocol { 
    static var : Self? {get} // an existing instance? 
    static var : Self {get} // a new instance 

    func instanceFunc() 
} 

extension Protocol { 
    static func staticFunc() { 
     (??).instanceFunc() 
    } 
} 
+0

バグのように見えますが、インスタンスメソッドでも同様の構文を使用できますが、クラスメソッドや静的プロパティでは機能しません。 [あなたはそれを提出しましたか?](http://bugreport.apple.com) – rickster

+0

私はそれをコンパイルすることはできません。編集されました。 – Jessy

+0

私はあなたの更新されたC#のサンプルコードは、私の 'typealias InstanceType'コードとまったく同じだと思います。行動の違いはありますか?あなたのC#で 'Subclass.instance()'を呼び出した場合、戻り値の型(実装ではなく変数型)が 'Class'になりますか? –

答えて

6

それが言うように、あなたがこれを行うには、正当な理由のためにすることはできません。あなたは約束を守ることは証明できません。

class AnotherSubclass: Class {} 
let x = AnotherSubclass().instance 

のでx(つまりSelfです)あなたのプロトコルに従ってAnotherSubclass次のようになります。これを考慮してください。しかし実際にはSubclassとなりますが、これは全く異なるタイプです。クラスがfinalでない限り、このパラドックスを解決することはできません。これは迅速な制限ではありません。この制限は、型の矛盾を許容するため、正しい型のシステムに存在します。

一方、instanceは、すべてのサブクラス(つまりスーパークラス)で一定の型を返すことを約束します。今

protocol Protocol { 
    typealias InstanceType 
    var instance: InstanceType {get} 
} 

class Class: Protocol { 
    var instance: Class {return Subclass()} 
} 

class Subclass: Class {} 
class AnotherSubclass: Class {} 
let x = AnotherSubclass().instance 

x明確タイプClassのです:あなたは、関連するタイプでは、それを行います。 (これはまた別のランダムなサブクラスであることもありますが、これは奇妙なことですが、それはコードのことです)。

私は実際にそうしてはいけないときにサブクラス化を使用していることを示唆しています。 Compositionとプロトコルはおそらくこの問題をSwiftでより良く解決するでしょう。 Subclassが実際にClassのサブクラスである必要がある理由があるかどうか自問してください。それは同じプロトコルに準拠した独立型ですか?サブクラスを取り除き、プロトコルに焦点を当てると、あらゆる種類の問題が解消されます。


私はこれ以上のことを考えており、あなたが探しているものを得る方法があるかもしれません。すべてのサブクラスでinstanceが実装されているというよりも、拡張子としてinstanceを付けてください。もしあなたが何か他のものを返そうとするなら、あなたはそれを上書きすることができます。

protocol Protocol { 
    init() 
} 

class Class: Protocol { 
    required init() {} 
    var instance: Class { return Subclass() } 
} 

extension Protocol { 
    var instance: Self { return self.dynamicType.init() } 
} 

class Subclass: Class {} 

これは継承の問題を(あなたがこの方法を「間違った型を返すAnotherClass」同じを作成することはできません)かわし。

+0

私が作ろうとする約束は、インスタンスが自己またはT:自己のいずれかを返すことです。 「自己」という言葉がはっきりしないのであれば謝りますが、私が欲しいものを表現する構文があれば、まだ分かりません。 – Jessy

+0

あなたはクラスでその約束を守ることはできません。私の 'AnotherSubclass'の例を見てください。これは構文の問題ではありません。タイプの問題です。あなたが矛盾なく言っていることを表現する方法はありません。 'Class'、' Subclass'、そして 'AnotherSubclass'がすべて構造体(または継承を持たない)であれば、それらはすべて一貫して' instance'を実装できます。しかし、あなたが相続財産を混ぜ合わせるとき、あなたはもう約束を守れません。 –

+0

ありがとうございます。私は今、問題はクラスがプロトコルを実装していることを表現できないことに由来していることがわかりました。 (私はそれを知っていましたが、これまでのところ問題は発生していませんでした)。これは、プロトコルのコンセプトが進化するにつれて、これが将来解決されると考えています。 また、私が知る限り、抽象的なコアデータエンティティを使用するためには、継承に対処する必要があります。 – Jessy

2

これは実際には理にかなって、あなたが実際にこのようなすべてのサブクラスのためSelfを返すようにしたくない場合は動作します:

protocol Protocol : class { 
    typealias Sub : Self 
    var instance: Sub {get} 
} 

あなたのプロトコルが自身のサブクラスである必要がありtypealiasを定義することを意味します。次のコードはうまく動作します:

class Class: Protocol { 
    var instance: Class {return Subclass()} 
} 

class Subclass: Class {} 

Class().instance // Returns SubClass() 

上記のコードはエラー、私はバグだと思う

error: inheritance from non-protocol, non-class type '`Self`' 

でコンパイルされません。しかし、Selfは、クラス型として宣言されているため。

protocol Protocol : class { 
    typealias Sub : Class 
    var instance: Sub {get} 
} 

だけクラス自体は今までそれに従わなければならないので、あなたは、プロトコル自体の多くを持っていません。ただし、それは何らかの形でこのように動作させることができます。

関連する問題