web-dev-qa-db-ja.com

あるプロトコルを別のプロトコルに準拠する具象型として使用することはサポートされていません

ジェネリックとプロトコルを混ぜようとしていますが、本当に苦労していますxD

Android/Javaプロジェクトに特定のアーキテクチャを実装しており、Swift/iOSプロジェクトに合うように書き直そうとしています。しかし、私はこの制限を見つけました。

ProtocolA

protocol ProtocolA {

}

ProtocolB

protocol ProtocolB : ProtocolA {

}

ImplementProtocolA

class ImplementProtocolA <P : ProtocolA> {

    let currentProtocol : P

    init(currentProtocol : P) {
        self.currentProtocol = currentProtocol
    }

}

ImplementProtocolB

class ImplementProtocolB : ImplementProtocolA<ProtocolB> {

}

したがって、ProtocolBProtocolA、このエラーが発生します:

プロトコル「ProtocolA」に準拠する具象型として「ProtocolB」を使用することはサポートされていません

1この「制限」の理由はありますか?

2これを実装するための回避策はありますか?

3ある時点でサポートされますか?

-UPDATED-

同じ問題の別の変形、私は思う:

プロトコルの表示

protocol View {

}

protocol GetUserView : View {
    func showProgress()
    func hideProgress()
    func showError(message:String)
    func showUser(userDemo:UserDemo)
}

プレゼンタープロトコル

protocol Presenter {
    typealias V : View
}

class UserDemoPresenter : Presenter {
    typealias V = GetUserView
}

Error:

UserDemoPresenter.Swift「V」(別名「GetUserView」)と一致する可能性のある一致が「View」に適合していません

それは何ですか??適合!

GetUserViewの代わりにViewを使用しても、コンパイルされません。

class UserDemoPresenter : Presenter {
    typealias V = View
}

UserDemoPresenter.Swift「V」(別名「View」)と一致する可能性のある一致が「View」に適合していません

xxDD本当にわかりません。

-UPDATED-

Rob Napierによって提案された解決策では、問題は修正されず、代わりに遅延します。

UserDemoPresenterへの参照を定義しようとすると、ジェネリック型を指定する必要があるため、同じエラーが発生します。

private var presenter : UserDemoPresenter<GetUserView>

プロトコル「GetUserView」に準拠した具象型として「GetUserView」の使用はサポートされていません

61

制限の根本的な理由は、Swiftにはファーストクラスのメタタイプがないことです。最も単純な例は、これが機能しないことです。

func isEmpty(xs: Array) -> Bool {
    return xs.count == 0
}

理論的には、このコードは機能する可能性があります。もしそれができれば、他の多くのタイプを作成できます(FunctorやMonadなど、Swift今日)では表現できません)。しかし、できません。あなたはSwiftこれを具体的な型に限定するのを助ける必要があります。多くの場合、ジェネリックでそれを行います:

func isEmpty<T>(xs: [T]) -> Bool {
    return xs.count == 0
}

Tはここでは完全に冗長であることに注意してください。表現しなければならない理由はありません。使用されたことはありません。しかし、Swiftは、抽象Arrayを具体的な[T]。同じことがあなたの場合にも当てはまります。

これは具象型です(インスタンス化されPが入力されるたびに具象型に変換される抽象型です):

class ImplementProtocolA<P : ProtocolA>

これは完全に抽象型で、Swiftには具象型に変換するルールがありません。

class ImplementProtocolB : ImplementProtocolA<ProtocolB>

具体的にする必要があります。これはコンパイルされます:

class ImplementProtocolB<T: ProtocolB> : ImplementProtocolA<T> {}

そしてまた:

class UserDemoPresenter<T: GetUserView> : Presenter {
    typealias V = T
}

後で問題に遭遇する可能性が高いという理由だけで、これらの構造体またはfinalクラスを作成すると、人生がずっと楽になります。プロトコル、ジェネリック、およびクラスポリモーフィズムの混合には、非常に鋭いエッジがいっぱいです。時々あなたは幸運で、それはちょうどコンパイルしません。予期しないものを呼び出すこともあります。

AnySequenceのちょっとした敬意 に興味があるかもしれません。


private var presenter : UserDemoPresenter<GetUserView>

これは依然として抽象型です。もしかして:

final class Something<T: GetUserView> {
    private var presenter: UserDemoPresenter<T>
}

問題が発生する場合は、ボックスを作成する必要があります。タイプを消去して抽象型を保持できるようにする方法については、「 プロトコルはそれ自体に準拠していませんか? 」を参照してください。ただし、具体的な型で作業する必要があります。最終的にプロトコルに特化することはできません。最終的には、ほとんどの場合、具体的な何かに特化する必要があります。

61
Rob Napier