2016-09-19 4 views
4

非自明な閉鎖に使用することができない私は、静的な初期化メソッドを持つクラスを持っているしたいと思います:「自己」は

class A { 

    required init() { 
    } 

    // this one works 
    class func f0() -> Self { 
    return self.init() 
    } 

    // this one works as well  
    class func f1() -> Self { 
    let create = { self.init() } // no error, inferred closure type is '() -> Self' 
    return create() 
    } 
} 

残念ながら、スウィフト3コンパイラが{ self.init() }よりも複雑な任意の閉鎖のための型を推論することができません。たとえば、次のように解決策はSelfを使用してクロージャを避けるためです

class func f3() -> Self { 
    let create = {() -> Self in // error: 'Self' is only available in a protocol or as the result of a method in a class; 
    let a = self.init() 
    return a 
    } 

    return create() 
} 

class func f4() -> Self { 
    let create = { 
    let a: Self = self.init() // error: 'Self' is only available in a protocol or as the result of a method in a class; 
    return a 
    } 

    return create() 
} 

class func f5() -> Self { 
    let create = {() -> A in 
    let a = self.init() 
    return a 
    } 

    return create() as! Self // error: cannot convert return expression of type 'A' to return type 'Self' 
} 

class func f2() -> Self { 
    let create = { 
    // error: unable to infer complex closure return type; add explicit type to disambiguate 
    let a = self.init() 
    return a 
    } 

    return create() 
} 

閉鎖型を指定しようとすると、変数の型を明示的またはSelfAからキャストエラーにつながります。

これはコンパイラの非常に不幸な制限のようです。それの背後に理由はありますか?この問題は将来のSwiftバージョンで修正される可能性がありますか?

+1

これは同じではありませんが、これはhttp://stackoverflow.com/questions/25645090と非常によく似ています/ protocol-func-returning-selfとなります。基本的な問題は、Swiftはコンパイル時に 'Self'の型を判断する必要がありますが、実行時にそれを決定したいと思っています。コンパイル時にすべてを解決できるなら、クラス関数がSelfを実行できるように幾分拡張されていますが、Swiftはあなたの型が*これらのいくつかの場合に正しいものでなければならないと常に証明することはできません。それは実際には間違っている可能性があるからです)。 –

+0

これはもう少し良くなると思っていますが、Swiftはこの種の複雑な継承を避けています(これらは非最終クラスなので、すべてのサブクラスを考慮する必要があります)。プロトコルは長期的に好きです。 Swift 4または5で完全に可能にしてください。 –

+0

@RobNapier _Swiftは、これらのケースのいくつかであなたのタイプが正しくなければならないとは必ずしも証明できません(時にはそれがいかに未知であるか、そのような場合の例はありますか? –

答えて

2

基本的な問題は、Swiftはコンパイル時にSelfのタイプを判断する必要がありますが、実行時にそれを判断する必要があるということです。コンパイル時にすべてを解決できればクラス関数がSelfを返すことができるように幾分拡張されていますが、Swiftはこれらのケースのいくつかであなたの型が正しくなければならないと常に証明することはできません(時には、実際には間違っている可能性があるため)。

たとえば、Self-returningメソッドをオーバーライドしないサブクラスを考えてみましょう。どのようにしてサブクラスを返すことができますか?それが何かに自己を渡す場合はどうなりますか?コンパイラが未知のサブクラスを与えられたときに、コンパイル時に静的に型をチェックする方法を教えてください。 (実行時およびモジュール境界を越えて追加できるサブクラスを含む)

これは少し良くなると思っていますが、Swiftはこの種の複雑な継承を邪魔します(これらは最終的なクラスではないので、可能なサブクラス)、プロトコルは長期的に好きなので、これはSwift 4または5で完全に可能であるとは思っていません。