2017-12-19 13 views
3

は、私が唯一それが両方のプロトコルに準拠しているためTestThingCを構造体へ適用される拡張機能を記述しようとしているこれらのプロトコルSwift 4では、複数のプロトコルに準拠するものにのみ適用される拡張機能を記述できますか?

protocol NamedThing{ 
    var name:String{ get } 
} 

protocol ValuedThing{ 

    associatedtype ValueType 

    var value:ValueType{ get } 
} 

そして、これらの構造体...

struct TestThingA : NamedThing { 
    let name = "TestThing" 
} 

struct TestThingB : ValuedThing { 

    typealias ValueType = Int 

    let value = 4 
} 

struct TestThingC : NamedThing, ValuedThing { 

    typealias ValueType = Int 

    let name = "TestThing" 
    let value = 4 
} 

を考えてみましょう。これらの作業の

いずれも、もちろん...

extension NamedThing & ValuedThing{ 
    func test(){ 
     print("Named thing \(name) has a value of \(value)") 
    } 
} 

extension Any where NamedThing & ValuedThing { 
    func test(){ 
     print("Named thing \(name) has a value of \(value)") 
    } 
} 

extension Any where Self is NamedThing, Self is ValuedThing{ 

    func test(){ 
     print("Named thing \(name) has a value of \(value)") 
    } 
} 

extension Any where Self == NamedThing, Self == ValuedThing{ 

    func test(){ 
     print("Named thing \(name) has a value of \(value)") 
    } 
} 

それでは、どの一つは、両方の(複数の)プロトコルに準拠したアイテムに適用される拡張機能を記述しないのでしょうか?あなたはプロトコルの1に制限された拡張子を定義することができ

答えて

4

extension NamedThing where Self: ValuedThing { 
    func test(){ 
     print("Named thing \(name) has a value of \(value)") 
    } 
} 

TestThingC().test() // compiles 

TestThingA().test() // error: Type 'TestThingA' does not conform to protocol 'ValuedThing' 
TestThingB().test() // error: Value of type 'TestThingB' has no member 'test' 
+2

これは技術的にプロトコルの1つに拡張されているにもかかわらず、実質的にはその組み合わせに拡張されています。つまり、拡張子ValuedThing where Self:NamedThingと同じ結果を得ます。 – rickster

+0

私は実際には、元々2つのwhere句で 'Any'を拡張することを考えましたが、コンパイラはそれを気に入らず、私の道を邪魔しました。それは面白いです...私は1つのプロトコルを拡張することを考慮しなかったし、まったく同じことをしたwhere節で他のプロトコルを使用することさえ考えませんでした。 @ricksterのように、注文は関係ありません。本当にきれい!受け入れられる! – MarqueIV

1

私はいつも他のプロトコルを継承する新しいプロトコルを作成することによって、これらの問題を解決しました。

protocol NamedValueThing: NamedThing, ValuedThing { } 
extension TestThingC: NamedValueThing { } 

extension NamedValueThing { 
    func test() { 
     print("\(value) \(name)") 
    } 
} 

//TestThingA().test() //error: value of type 'TestThingA' has no member 'test' 
//TestThingB().test() //error: value of type 'TestThingB' has no member 'test' 
TestThingC().test() //4 TestThing 
+0

これは私の最初の考えでしたが、実際にはNamedValueThingを実装するものは暗黙的にNamedThingとValuedThingを実装しますが、NamedThingとValuedThingを実装するものは暗黙的にNamedValueThingを実装しないため、手動で適用する必要があるそのメタプロトコル。私はその逆をしようとしています...手動でタグ付けしたものだけではなく、これらの2つのプロトコルを実装している*すべての項目のものを定義してください。理にかなっている? – MarqueIV

+0

はい、残念ながら、この方法の欠点は、明示的に新しいプロトコルに準拠する必要があることです。私はあなたの質問を理解した、私はちょうどそれが可能だったか見ていない。個人的には、新しいプロトコルに準拠するように型を拡張することは大きな努力だとは思わない。しかし、コンパイラにこれを理解させる方法にも興味があります。 – Yannick

+0

残念ながら、私たちは私たちに渡されているすべてのタイプを知らない。これらの2つのプロトコルに準拠していることがわかりました。実際、上記の@MartinRが示すように、かなり簡単です。プロトコルの1つを、他のプロトコルにも準拠しなければならないことを示す 'where'節で拡張します。要件が同じであるため、どの順序でも問題ありません。あなたが私に尋ねるとかなりきちんとしたトリック! – MarqueIV

関連する問題