26

亲爱的斯卡拉,

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

好的...

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在这样的匿名函数中使用呢?

4

1 回答 1

18

请参阅 Scala 参考 ( http://www.scala-lang.org/files/archive/nightly/pdfs/ScalaReference.pdf ) 的第 8.5 节。表达式{ case (a, b) => a + b }的解释根据预期的类型而不同。在您对它的定义中f1,创建了一个PartialFunction[(Int, Int), Int]被强制转换为 a 的 a Function1[(Int, Int), Int],即((Int, Int)) => Int,而在它的定义中f2创建了一个Function2[Int, Int, Int],即(Int, Int) => Int

这两种解释与您通常在匿名函数中使用 case 的两种情况有关。

一种是用于编写接受元组并处理其组件的匿名函数,就像您对f1. 一个示例是您传递给 a 上的foreachormap方法的函数Map,例如Map(1 -> 2, 3 -> 4) map { case (k, v) => k + v }

第二个是编写一个匿名函数,该函数match对其唯一的参数执行 a 。你f2正在这样做,但没有任何有用的方式。collect例如,传递给 的匿名函数就是一个例子List(1, -2, 3) collect { case x if x > 0 => -x }

请注意,两者可以结合使用,即类似功能f1也可以进行复杂匹配。例如,Map(1 -> 2, 3 -> 4) collect { case (k, v) if k < 2 => v }

编辑:res2由于元组而起作用。如果应用程序没有进行类型检查,编译器会在失败之前尝试将 args 包装在一个元组中。

但这仅适用于应用程序;正如您所发现的,这不是一般的转换。它不会尝试将值升级Function2[A, B, C]Function1[(A, B), C].

于 2013-10-20T14:46:14.457 回答