2016-03-23 10 views
1
protocol ProtocolA { 
    func someFunc() -> Any 
} 

protocol ProtocolB: ProtocolA { 
    var someVar: Any { get } 
} 

enum MyEnum<T: ProtocolA, U: ProtocolB> { 
    case A(T) 
    case B(U) 
} 

protocol DataObject { 
    ... 
} 

extension DataObject where Self: ProtocolB { 
    func doSomething() { 
     let x = MyEnum.B(self) 
     /// Compiler error: 
     /// Cannot invoke 'B' with an argument list of type '(Self)' 
    } 
} 

私は上記の理由で私にエラーが発生するのか分かりません。 不思議なことに、2つの列挙型ジェネリック制約のいずれかを削除して、列挙型を1つの制約で残しておけば、問題は解決します...従属プロトコルに関連した迅速な列挙型の汎用的な種類

ProtocolBはProtocolAを拡張しています。ジェネリック制約で使用する場合はサポートされていませんか?

答えて

2

エラーがある...私はまだかなりなぜ得ることはありません、しかし

enum MyEnum { 
    typealias T = ProtocolA 
    typealias U = ProtocolB 

    case A(T) 
    case B(U) 
} 

:これまでMyEnumを変更するUPDATE


は、問題を解決します少し誤解を招く。問題を単純化してそれを探索しよう。

protocol ProtocolA {} 

protocol ProtocolB: ProtocolA {} 

enum MyEnum<T: ProtocolA, U: ProtocolB> { 
    case A(T) 
    case B(U) 
} 

struct AThing: ProtocolA {} 

struct BThing: ProtocolB {} 

let bThing = BThing() 
let thing = MyEnum.B(bThing) // error: cannot invoke 'B' with an argument list of type '(BThing)' 

ここでは、DataObjectを必要とせずに同じ問題が発生しています。なぜこれは失敗するのですか?

MyEnumは一般的です。つまり、具体的な型を作成するには、型の種類がTUであることが必要です。これらのタイプに制約を与えました(1つはProtocolAに、もう1つはProtocolBに準拠しています)。

我々は、この行を取得:

let thing = MyEnum.B(bThing) 

thingは何タイプ?型推論では、Uが何であるか分かりますが、Tとは何ですか?

let thing: MyEnum<?, BThing> = MyEnum.B(bThing) 

はそれを動作するように、ここで十分な文脈だけではありませんので、我々は明示的にコンパイラに指示する必要があります。

let thing = MyEnum<AThing, BThing>.B(bThing) 

をそうthingの完全なタイプはMyEnum<OtherAThing, BThing>とは異なるタイプである、MyEnum<AThing, BThing>です。 (正確に[Int]ようlet xs = []は、明示的な型定義せずにコンパイルされません理由である、[String]とは異なるタイプである。)作品

あなたの第二の例は、汎用ではないので、何も問題はありません。バウンドtypealiasesだけの種類の名前を変更

enum MyEnum { 
    case A(ProtocolA) 
    case B(ProtocolB) 
} 

、彼らは新しいタイプを作成していない(非結合typealiasたい、またはなどスウィフト2.2呼び出して、associatedtype):それはに簡素化します。したがって、AにはProtocolAが、BにはいずれもProtocolB、すべてのMyEnumには同じタイプが割り当てられます。

コンパイラが混乱しているため、このエラーは残念です。これを最も基本的なケースに単純化すると、より明確なエラーが発生します。これはあなたの例とまったく同じ理由で失敗します。

enum MyEnum<T> { 
    case A 
} 

let x = MyEnum.A // error: generic parameter 'T' could not be inferred 
+0

説明をありがとう!これは私がここでもっと頻繁に見たいと思っているゴールドの答えです;実際にはエラーは非常に不幸です:) 今は 'typealias'の解決策に固執します。関連するプロトコルに準拠したものを私に渡すことができます。 (ジェネリックのソリューションのように)。私は、このようなことをするのではなく、入力を1つのプロトコルに限定することを制限していると思います。 '' T:ProtocolA、T:ProtocolC> '? – Cabus

+0

私はあなたがその制約から何を期待しているのか分かりません。あなたは「または」を意味しますか?それが事実なら、Tのタイプは何ですか?どのような方法で呼び出すことができますか? 1つのタイプを持つ必要があります。オーバーラップするプロトコルのグループがいくつかある場合、それらがすべて準拠している別のプロトコルを作成できます。 –

+0

遅れて申し訳ありません。私は以来、別のソリューションに移行しました。とにかく助けてくれてありがとう。ただし、 こちらをご覧くださいhttp://www.youtube.com/watch?v=gaXSbqo3iKA&t=2m54s それはうまくいくはずですか? – Cabus

関連する問題