2016-05-27 3 views
2

匿名クロージャー引数の使用法を理解する上で問題があります。私が遊び場にこの不自然な例を手早く説明するために:匿名クロージャー引数のサブセットのみにアクセスする

typealias SomeClosureType = (
thing0: Float, 
thing1: Float, 
thing2: Float, 
thing3: Float, 
thing4: Float, 
thing5: Float 
) -> Void 

class MyClass { 

    var someClosure: SomeClosureType! 

    init() { 
     // This is OK but long 
     self.someClosure = { (thing0: Float, thing1: Float, thing2: Float, thing3: Float, thing4: Float, thing5: Float) in self.handleThing0(thing0) } 

     // Compiler error: "cannot assign value of type '(Float) ->()' to type 'SomeClosureType!'" 
     self.someClosure = { self.handleThing0($0) } 
    } 

    func handleThing0(thing0: Float) { 
     print("\(thing0)") 
    } 
} 

let myInstance = MyClass() 
myInstance.someClosure(thing0: 0, thing1: 1, thing2: 2, thing3: 3, thing4: 4, thing5: 5) 

をだから、基本的に私は、クロージャ内からの匿名の閉鎖の引数にアクセスしようとすると、私はこのエラーを取得します。私は何が欠けていますか?

答えて

3

コンパイラには、クロージャが他の5つの「もの」を決して参照しないので、クロージャが単一のfloatパラメータしか処理していないように見えます。したがって、見かけ上の不一致があり、コンパイラはそれをエラーとしてフラグを立てます。

有効な方法で6つの入力パラメータをすべて参照すると、エラーは表示されなくなります。これは単に、このような追加のパラメータが有効になります参照し、あなたが書くべきものではないが、例えば:

self.someClosure = { self.handleThing0($0); _ = [$1,$2,$3,$4,$5] } 

あなたがのために行くされているものを表現するための最短/最良の方法は次のとおりです。

self.someClosure = { thing0, _, _, _, _, _ in self.handleThing0(thing0) } 

ここで、それぞれ_は無視する値を表しますが、コンパイラはフロート値であると推測できます。

+0

ありがとう、ダニエル。あなたは問題をよく説明したと思います。私は、コンパイラーがクロージャー引数のサブセットのみを参照できるように十分にスマートであることを望みます。私はこれが設計上のものか何らかの技術的な限界かと思います。 –

+0

@JohnScaloええ、私は完全に参照するパラメータのサブセットのみを許可するケースを見ることができます。一方、1)コンパイラは間違って何か重要なことを処理していないと想定しなければならず、コンパイラが間違いの可能性があるとフラグを立てるほうが良いということを意味します2)Swiftは非常に強い型や契約に向いています。したがって、開発者がパラメータ "A"とパラメータ "B"を扱うはずのクロージャを指定し、 "A"だけを扱うクロージャを指定する場合、それはSwiftの性質とかなり矛盾しているとみなすことができます。 –

+0

@DanielHall、行動は容認できますが、それはSwiftチームのバグとみなされます。 – zneak

0

ここでは何をしようとしているのか100%確信していませんが、いくつかの情報を提供しようとしています。一番上のもの(長いもの)は、実際には正しいものです。だから、クロージャーは実際には、あなたの現在のスコープ内のコードの小さなブロックとして、よりコンパクトに設計された関数です。あなただけthing0プロパティを使用して意図した場合は、単に使用して残りの部分を無視することができ_、例えば:

self.someClosure = { thing0, _ in 
    self.handleThing0(thing0) 
} 

あなたはサイクルを保持取得を開始するために、その本当に簡単としてクロージャを使用するときに注意する必要がありますが、原因ARCなど。あなたの第二の閉鎖で

+1

アンダースコアは引数の残りの部分を無視しないため、無視される引数のそれぞれにアンダースコアが必要です。 –

0

あなたはので、コンパイラはあなたの匿名の閉鎖を考慮にhandleThing0()(Float) ->()の署名を取って、一つだけ引数を取ると仮定だけ$0使用し、コンパイラは、渡され(Float) ->()$0として閉鎖の署名があることを知っていますhandleThing0()には何も返されません。

次に、タイプが(Float, Float, Float, Float, Float, Float) -> Voidのプロパティに(Float) ->()クロージャを割り当てようとします。これは、closure take 5引数が要求より少なくなるため不可能なため、エラーです。

2

この特定の問題は、迅速な進化に伴い定期的に発生します。迅速な進化 swift.org>経由

9:16で2016年5月13日、オン

、ジョーGroffの書いた:これは、使用を奨励

クリス・ラットナーはthis is considered a bug in the compiler, but it requires significant effort to fixがと言いましたオプションのクロージャよりも空のクロージャがあります。これは議論の場です。一般的に、私はオプションの値を正確に置き換えることができない場合には、 というオプションを避けるようにしています。 さらに、ほとんどのCocoa補完ハンドラはオプションではありません。

代替方法はこれを行わないことですが、合理的に空になる可能性のあるクロージャーは実際にはオプションであることを推奨します。 "{_ in}"を避けるために、空白を返すクロージャを持つココア関数を としてインポートする必要があります。

+1。一般に、私たちは今暗黙の引数を許すべきだと私は考えています。今日は のようにすべての暗黙の$ n変数を使用する必要はありません。これらはすべて有効である必要があります。

let _:() ->() = {}
let _: (Int) ->() = {}
let _: (Int, Int) -> Int = { 5 }
let _: (Int, Int) -> Int = { $0 }
let _: (Int, Int) -> Int = { $1 }

私は同意するが、私は、これはコンパイラの明らかなバグであると考えています。私は 提案が必要とは思わない。

残念ながら、修正するために非自明である...

-Chris

修正が起こるまでは、あなたが最初の形式で立ち往生しています。

関連する問題