2017-08-21 12 views
1

私はいくつかのフレームワークに取り組んでおり、問題に直面しています。一般的な補完が非汎用として渡される

私は公共のプロトコルがあります

public protocol MyPublicProtocol1 { 
} 

そして、別のものを、ウィッヒは、渡された汎用的な引数を持つ関数が含まれています。一般的な引数には制約があります - 引数の型は最初の公開プロトコルを実装する必要があります。

次に、公開クラスではないプロトコルを実装しています。一般的な引数でその関数内私は、一般的な議論をしませ取る別のものを呼び出し、そのように見ている:

class MyPublicProtocol1Impl: MyPublicProtocol1 { 
} 

class MyPublicProtocol2Impl: MyPublicProtocol2 { 
    func someFunc<T: MyPublicProtocol1>(completion: (T) ->()) { 
     anotherFuncWith(completion: completion) 
    } 
} 

そしてもちろん、私はエラーを持っている:

func anotherFuncWith(completion: (MyPublicProtocol1) ->()) 

そして、ここでは、実装は次のようになります。最後の文字列に

私は好きではない、一般的な引数でsomeFunc(完了:)を宣言することはできません。MyPublicProtocol1Implクラスは、公開してはならないので

func someFunc(completion: (MyPublicProtocol1Impl) ->()) 

。また、anotherFuncWith(完了:)も何らかの理由で汎用引数を取ることはできません。

やや"変換" する方法がある(Tを:MyPublicProtocol1) - >()完了ちょうど(MyPublicProtocol1)ことにする - >()は?

何か助けやアドバイスをいただければ幸いです。私の話を読んでくれてありがとう!

+0

あなたの試行されたソリューションで解決してください。多くの場合、最良のソリューションは私の現在のアプローチとは異なるものです。 – PeejWeej

答えて

0

あなたは明らかに真実ではないものを求めました。

func anotherFuncWith(completion: (MyPublicProtocol1) ->()) 

これは、任意のMyPublicProtocol1を受け取ることができる方法を受け入れる:あなたはメソッドを持っています。

(T: MyPublicProtocol1) ->() 

anotherFuncWithこれが定義されていないその時点でTではない何かを渡すことがあります。それから、種類の方法がそれを渡します。より具体的にするために、ここでほとんどのものを取り除き、MyPublicProtocol1Anyにしましょう(単純なプロトコルを選択するだけです)。

func anotherFuncWith(completion: (Any) ->()) { 
    completion("This is a string which is an Any, so that's fine") 
} 

func someFunc<T: Any>(completion: (T) ->()) { 
    anotherFuncWith(completion: completion) 
} 

これは、例のようにコンパイルできません。今度は、コンパイルした場合、私ができることを考えてみましょう。私は呼び出すことができます。

func complete(x: Int) ->() { 
    print(x + 1) 
} 

someFunc(completion: complete) 

だから今anotherFuncWith通話complete追加することはできませんStringを、渡します。クラッシュ。

ここでの根底にある問題は、covariance and contravarianceを後方に持っていることです。

どうすれば修正できますか?あなたが本当に意味するものに依存します。このコードは少し奇妙です。あなたはTの実際のタイプを気にしていますか?あなたは決してそれを使用しているようです。あなたが気にしない場合は、単にプロトコルを使用します。

public protocol MyPublicProtocol2 { 
    func someFunc(completion: (MyPublicProtocol1) ->()) 
} 

あなたがPATを使用して、実際の型を気にしない場合:

public protocol MyPublicProtocol2 { 
    associatedtype T: MyPublicProtocol1 
    func someFunc(completion: (T) ->()) 
} 

それともあなたは、プロトコルが必要かどうかを再考することをお勧めしますここには全く。私はしばしば、彼らがまだそれらを必要としないときにプロトコルのために人々が達するのを見つける。これらのプロトコルを複数実装していますか?渡される複数の型がありますか?もしそうでなければ、私は単純化して、現在のコードであなたが解決している本当の問題を抱えているときにのみ汎用/プロトコルに行きます。 (あなたはそれらを必要とする場合があり、これは、彼らが過剰設計したとき、多くの人々が有用であることが判明したことをちょうど私の株式のアドバイスである。)

0

これを回避するために汚いやり方は私だけだろう

func someFunc<T: MyPublicProtocol1>(completion: (T) ->()) { 
    anotherFuncWith { (thing) in 
     if let tThing = thing as? T { 
      completion(tThing) 
     } 
    } 
} 

ですこれならあなたは非常にのようにそれを囲むコードが間違いないと確信しています。

また、これも機能します。私はあなたが実際にそれはあなたの問題を解決するかどうか、私はよく分からないので、何をしようとしてわからないよ、私はあなたが意図している使用状況やあなたがしようとしている根本的な問題についてより明確であることをお勧めします

func anotherFuncWith<T: MyPublicProtocol1>(completion: (T) ->()) { 

} 

class MyPublicProtocol2Impl: MyPublicProtocol2 { 

    func someFunc<T: MyPublicProtocol1>(completion: (T) ->()) { 
     anotherFuncWith(completion: completion) 
    } 
} 
関連する問題