親愛なるScala、
_scala> val f1: ((Int, Int)) => Int = { case (a, b) => a + b }
f1: ((Int, Int)) => Int = <function1>
scala> val f2: (Int, Int) => Int = { case (a, b) => a + b }
f2: (Int, Int) => Int = <function2>
_
え?!
_scala> f1(1, 2)
res2: Int = 3
_
OK...
_scala> def takesIntInt2Int(fun: (Int, Int) => Int) = fun(100, 200)
takesIntInt2Int: (fun: (Int, Int) => Int)Int
scala> def takesTuple2Int(fun: ((Int, Int)) => Int) = fun(100, 200)
takesTuple2Int: (fun: ((Int, Int)) => Int)Int
scala> takesIntInt2Int(f2)
res4: Int = 300
scala> takesIntInt2Int(f1)
<console>:10: error: type mismatch;
found : ((Int, Int)) => Int
required: (Int, Int) => Int
takesIntInt2Int(f1)
^
scala> takesTuple2Int(f1)
res6: Int = 300
scala> takesTuple2Int(f2)
<console>:10: error: type mismatch;
found : (Int, Int) => Int
required: ((Int, Int)) => Int
takesTuple2Int(f2)
_
正しい。そして今、これを見てください!
_scala> takesTuple2Int { case (a, b, c) => a + b + c }
<console>:9: error: constructor cannot be instantiated to expected type;
found : (T1, T2, T3)
required: (Int, Int)
takesTuple2Int { case (a, b, c) => a + b + c }
^
scala> takesIntInt2Int { case (a, b, c) => a + b + c }
<console>:9: error: constructor cannot be instantiated to expected type;
found : (T1, T2, T3)
required: (Int, Int)
takesIntInt2Int { case (a, b, c) => a + b + c }
_
のように、srsly? o_Oどちらもrequired: (Int, Int)
エラーになります。
では、なぜそのような無名関数でcase
を使用するのでしょうか。
Scalaリファレンス( http://www.scala-lang.org/files/archive/nightly/pdfs/ScalaReference.pdf )のセクション8.5を参照してください。式{ case (a, b) => a + b }
は、予想されるタイプに基づいて異なる方法で解釈されます。_f1
_の定義では、PartialFunction[(Int, Int), Int]
にキャストされるFunction1[(Int, Int), Int]
が作成されました。 _((Int, Int)) => Int
_に対し、_f2
_の定義では、_Function2[Int, Int, Int]
_、つまり_(Int, Int) => Int
_が作成されました。
これらの2つの解釈は、無名関数で一般的にユースケースを使用する2つの状況に関連しています。
1つは、_f1
_で行ったように、タプルを受け入れてそのコンポーネントで動作する無名関数を作成するためのものです。例としては、foreach
のmap
またはMap
メソッドに渡す関数があります。 Map(1 -> 2, 3 -> 4) map { case (k, v) => k + v }
。
2つ目は、唯一のパラメーターでmatch
を実行する無名関数を作成するためのものです。あなたの_f2
_はこれを行っていますが、有用な方法ではありません。例として、collect
に渡される無名関数があります。 List(1, -2, 3) collect { case x if x > 0 => -x }
。
この2つを組み合わせることができることに注意してください。つまり、_f1
_のような関数は複雑なマッチングも実行できます。たとえば、Map(1 -> 2, 3 -> 4) collect { case (k, v) if k < 2 => v }
。
編集:_res2
_はタプリングのために機能します。アプリケーションがチェックを入力しない場合、コンパイラーは失敗する前にタプルで引数をラップしようとします。
しかし、それはアプリケーションのためだけに試みられています。あなたが発見したように、それは一般的な変換ではありません。値_Function2[A, B, C]
_をFunction1[(A, B), C]
にアップグレードしようとはしません。