2017-02-16 3 views
0

説明できないメソッドで問題が発生しました。ここでは、問題を示し、いくつかのテストコードは次のとおりです。同じプロトコルのインスタンスを受け付けないメソッドの型としてスウィフトプロトコルが使用されました

protocol Base {} 
protocol Extended: Base {} 

struct Instance:Extended {} 

let anInstance = Instance() 
let instanceOfBase = anInstance as Base 
let instanceOfExtended = anInstance as Extended 

func aMethod<T:Base>(_ instance:T) {} 

aMethod(anInstance) 
aMethod(instanceOfBase) // Error - Cannot invoke 'aMethod' with an argument list of type '(Base)' 
aMethod(instanceOfExtended) // Error - Cannot invoke 'aMethod' with an argument list of type '(Extended)' 

私はなどのプロトコル、ジェネリック、上で読んだのApple DOCOによるaMethod()Baseプロトコルに準拠する任意のオブジェクトを受け入れる必要があります。それでも、私はそれらをBaseまたはExtendedにキャストした両方のインスタンスを拒否します。

誰でもこれを説明できますか?また

func aMethod2(_ instance:Base) {} 
aMethod2(anInstance) 
aMethod2(instanceOfBase) 
aMethod2(instanceOfExtended) 

作品細かいので、違いがBaseまたは<T:Base>に(しゃれを言い訳)instance引数がベースとされているかどうかのようです。

ここでジェネリックを宣言する理由は誰でも質問してください。

func addViewController<T:ModelObject>(_ stack:inout [UIViewController], 
           object:T?, 
           controller:DetailsViewController<T>?, 
           storyboardId:String) {... 

ご覧のとおり、いくつかの引数を同じタイプに制限したいと思います。したがって、単にベースを指定するのではなく、ジェネリックを使用します。

+0

[プロトコルがそれ自体に準拠していないためです](http://stackoverflow.com/q/33112559/2976878)。 – Hamish

答えて

1

Tは、コンクリート型

<T:Base>上の制約であるプレースホルダのタイプT上の制約です。 Tは、Baseプロトコルに準拠した具体的な型(クラス、enumまたはstruct、たとえばInstance)でなければなりません。プレースホルダタイプTBaseプロトコルにすることはできません。

aMethod<T:Base>(:)は、コンパイル時にBaseプロトコルに準拠する型の変数で呼び出される必要があります。 aMethod<T:Base>(:)は、タイプがBaseであることがわかっている変数では呼び出すことができません。

次のコード行は、構造型InstanceanInstanceという名前の変数をインスタンス化します。

let anInstance = Instance() 

aMethod(anInstance)anInstanceBaseプロトコルに準拠コンクリート型Instanceであるためコンパイル。

次のコード行は、プロトコルタイプBaseinstanceOfBaseという名前の変数をインスタンス化します。

let instanceOfBase: Instance = anInstance as Base 

aMethod(instanceOfBase)instanceOfBaseBaseプロトコルに準拠コンクリート型ではないので、コンパイルされません。プロトコルタイプはBaseです。

問題を説明できない別のスニペットがあります。この場合、base引数は、プロトコルタイプがBaseであることだけがわかります。

func aMethod(base: Base) { 
    aMethod(base) // Cannot invoke 'aMethod' with an argument list of type '(Base)' 
} 
+0

しかし、 'instanceOfBaseはBase'で、' instanceOfExtendedはBase'です。だから 'instanceOfBase'が' Base'の場合、ジェネリックスのドキュメントに従って 'Base'を確認する引数を受け入れるメソッドに渡すことができないのですか? – drekka

+0

しかし、コンパイラは 'instanceOfBase'を' Baseに準拠するもののインスタンス 'と見なしてはいけません。これは、 'Base'を具体的な型として扱うことを決定するように思えますが、そうではありません。それを効果的に 'Any 'またはそれに類するものとして扱うべきとき。 – drekka

+0

私は ''をタイプ 'T'の制約と解釈します。 'T'は' Base'プロトコルに従った具体的な型でなければなりません。 'T'は' Base'プロトコルに準拠した型ではありません。 –

1

ええ、私はあなたがこれをやっている理由を実際には知りません。

さんが言ってみましょう:あなたはBaseプロトコルに準拠する任意のインスタンスを受け入れるようにaMethodをしたい

  • を、そしてあなただけ作ることができ、それfunc aMethod(_ instance: Base) {}
  • あなたはジェネリックメソッドを使用し、関数内の型情報を保存したい
  • プロトコルの具体的な実装のインスタンスを渡します。

func aMethod<T:Base>(_ instance:T) {}はそれがBaseを準拠タイプTのインスタンスを期待しています意味しますのでご注意ください。 BaseまたはExtendedは有効なタイプです。

あなたがここでやっていることは、その力のないジェネリックを使っていることです。どちらが理にかなっていません。より現実的なシナリオを提供できる場合を除きますか?

+0

より現実的な例は 'func aMethod (_インスタンス:T、anotherThing:SomeType )'です。基本的に私の元のコードでは、いくつかのメソッド引数を持っていました。どこに 'T'をタイプするのか、ジェネリックタイプをどこに入れるのでしょうか。私はコンパイラがすべての引数が同じ型を使用していることを検証するようにしたかったのです。 – drekka

+0

たとえば、タイプが 'MyT:Base'の場合、' aMethod(_インスタンス:MyT、anotherThing:SomeType ) 'のように見えますが、' Base'を実装するクラスがいくつかあります。ジェネリック医薬品は答えのようだった。 – drekka

+0

私はこのようなプロトコルを使用している理由は、いくつかの実装が存在する可能性があり、どの実装が渡されたか気にしないコードに基づいてプロトコルに基づいて宣言したいのです。テストの観点からもいいアイデアです。 @Drekka右。 – drekka

関連する問題