ジェネリックとプロトコルを混ぜようとしていますが、本当に苦労しています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> {
}
したがって、ProtocolBをProtocolA、このエラーが発生します:
プロトコル「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」の使用はサポートされていません
制限の根本的な理由は、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>
}
問題が発生する場合は、ボックスを作成する必要があります。タイプを消去して抽象型を保持できるようにする方法については、「 プロトコルはそれ自体に準拠していませんか? 」を参照してください。ただし、具体的な型で作業する必要があります。最終的にプロトコルに特化することはできません。最終的には、ほとんどの場合、具体的な何かに特化する必要があります。