2つのプロトコルがあるとします。
_protocol TheirPcol {}
protocol MyPcol {
func extraFunc()
}
_
私がやりたいのは、「TheirPcol」のプロトコル拡張機能を作成することです。これにより、「TheirPcol」に準拠するものすべてにextraFunc()
を機能させることができます。だからこのようなもの:
_extension TheirPcol : MyPcol { // Error 'Extension of protocol 'TheirPcol' cannot have an inheritance clause.
func extraFunc() { /* do magic */}
}
struct TheirStruct:TheirPcol {}
let inst = TheirStruct()
inst.extraFunc()
_
これのキッカーは、「TheirPcol」、「TheirStruct」はすべて、私が制御しない外部APIによって処理されるということです。したがって、インスタンス「inst」が渡されます。
これはできますか?それとも私はこのようなことをしなければならないでしょうか?
_struct TheirStruct:TheirPcol {}
let inst = TheirStruct() as! MyPcol
inst.extraFunc()
_
自分がしていることをしたい理由が2つあるようです。最初のユースケースでは、Swiftを使用すると、やりたいことを実行できますが、2番目のユースケースではあまりきれいにできません。2つ目のカテゴリに当てはまると思いますが、両方を通過します。
TheirPcol
の機能の拡張これを行う理由の1つは、単にTheirPcol
に追加の機能を提供することです。コンパイラエラーが言うように、他のプロトコルに準拠するようにSwiftプロトコルを拡張することはできません。ただし、TheirPcol
を拡張することはできます。
_extension TheirPcol {
func extraFunc() { /* do magic */ }
}
_
ここでは、TheirPcol
に準拠するすべてのオブジェクトにメソッドextraFunc()
を与え、デフォルトの実装を与えています。これにより、TheirPcol
に準拠するオブジェクトの機能を拡張するタスクが実行され、独自のオブジェクトにも適用したい場合は、オブジェクトをTheirPcol
に準拠させることができます。ただし、多くの状況では、MyPcol
をプライマリプロトコルとして維持し、TheirPcol
をMyPcol
に準拠しているものとして扱います。残念ながら、Swiftは現在、他のプロトコルへの適合を宣言するプロトコル拡張をサポートしていません。
TheirPcol
オブジェクトをMyPcol
のように使用する実際にMyPcol
の存在が本当に必要なユースケース(ほとんどの場合はユースケース)では、私が認識している限り、目的の操作を行うための明確な方法はまだありません。ここにいくつかの機能しているが理想的ではない解決策があります:
TheirPcol
のラッパー面倒になる可能性のあるアプローチの1つは、次のようなstruct
またはclass
を使用することです。
_struct TheirPcolWrapper<T: TheirPcol>: MyPcol {
var object: T
func extraFunc() { /* Do magic using object */ }
}
_
既存のオブジェクトインスタンスをMyPcol
に準拠させる必要がある場合は、例のように、キャストの代わりにこの構造体を理論的に使用できます。または、MyPcol
をジェネリックパラメーターとして受け入れる関数がある場合は、TheirPcol
を取り込んでTheirPcolWrapper
に変換し、それをMyPcol
を受け取る他の関数。
もう1つ注意すべき点は、TheirPcol
のオブジェクトが渡されている場合、最初に明示的な型にキャストしないとTheirPcolWrapper
インスタンスを作成できないことです。これは、Swiftのいくつかのジェネリックの制限によるものです。したがって、このようなオブジェクトは代わりになる可能性があります。
_struct TheirPcolWrapper: MyPcol {
var object: MyPcol
func extraFunc() { /* Do magic using object */ }
}
_
これは、与えられたTheirPcolWrapper
の明示的なタイプを知らなくても、TheirPcol
インスタンスを作成できることを意味します。
ただし、大規模なプロジェクトの場合、これらの両方が非常に速く混乱する可能性があります。
さらに別の理想的でない解決策は、TheirPcol
に準拠していることがわかっていて、サポートしたいことがわかっている各オブジェクトを拡張することです。たとえば、ObjectA
およびObjectB
がTheirPcol
に準拠していることがわかっているとします。以下のように、MyPcol
の子プロトコルを作成し、両方のオブジェクトの準拠を明示的に宣言できます。
_protocol BridgedToMyPcol: TheirPcol, MyPcol {}
extension BridgedToMyPcol {
func extraFunc() {
// Do magic here, given that the object is guaranteed to conform to TheirPcol
}
}
extension ObjectA: BridgedToMyPcol {}
extension ObjectB: BridgedToMyPcol {}
_
残念ながら、このアプローチは、サポートしたいオブジェクトが多数ある場合、またはオブジェクトがどうなるかを事前に把握できない場合は機能しません。 type(of:)
を使用してメタタイプを取得することはできますが、指定されたTheirPcol
の明示的なタイプがわからない場合にも問題になります。
Swift 4.に含めることが受け入れられた提案である Conditional conformances を確認する必要があります。具体的には、この提案は、次の拡張機能を持つ機能の概要を示しています。
_extension Array: Equatable where Element: Equatable {
static func ==(lhs: Array<Element>, rhs: Array<Element>) -> Bool { ... }
}
_
これはあなたが求めていることではありませんが、下部には「プロトコルに準拠するようにプロトコルを拡張する」と呼ばれるサブセクションがある「代替案が検討されました」が見つかります。次の例を示します。
_extension Collection: Equatable where Iterator.Element: Equatable {
static func ==(lhs: Self, rhs: Self) -> Bool {
// ...
}
}
_
次に、次のように述べています。
このプロトコル拡張は、Equatable要素のコレクションをEquatableにします。これは、有効に活用できる強力な機能です。プロトコル拡張の条件適合を導入すると、適合の重複の問題が悪化します。これは、上記のプロトコル拡張の存在が、コレクションに準拠する型が、Equatable、条件付き、またはそれ以外への独自の適合を宣言できないことを意味すると言うのは不合理です。
条件付きに準拠する機能を求めているのではないことに気づきましたが、これは準拠するように拡張されているプロトコルの議論に関して私が見つけることができる最も近いものです他のプロトコルに。