“case”匿名函数在 Scala 中是如何真正工作的?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/19478244/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-22 05:46:31  来源:igfitidea点击:

How does a "case" anonymous function really work in Scala?

scalapattern-matching

提问by Michal Rus

Dеar 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>

huh?!

啊?!

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)

Right. And now, look at this!

对。现在,看看这个!

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 }

Like, srsly? o_O Both result in required: (Int, Int)error.

比如,srsly?o_O 两者都会导致required: (Int, Int)错误。

Why then use caseat all in such anonymous functions?

那么为什么要case在这样的匿名函数中使用呢?

采纳答案by wingedsubmariner

See section 8.5 of the Scala reference (http://www.scala-lang.org/files/archive/nightly/pdfs/ScalaReference.pdf). The expression { case (a, b) => a + b }is interpreted differently based on the expected type. In your definition of f1it created a PartialFunction[(Int, Int), Int]which was cast to a Function1[(Int, Int), Int], i.e. ((Int, Int)) => Intwhereas in the definition of f2it created a Function2[Int, Int, Int], i.e. (Int, Int) => Int.

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

These two interpretations relate to the two situations where you would commonly use case in an anonymous function.

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

One is for writing anonymous functions that accept tuples and work on their components, as you did with f1. An example would be the function you pass to the foreachor mapmethod on a Map, e.g. Map(1 -> 2, 3 -> 4) map { case (k, v) => k + v }.

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

The second is for writing an anonymous function that does a matchon its sole parameter. Your f2is doing this, but not in any useful way. An example would be the anonymous function passed to collect, e.g. List(1, -2, 3) collect { case x if x > 0 => -x }.

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

Note that the two can be combined, that is functions like f1can do complex matching as well. For example, Map(1 -> 2, 3 -> 4) collect { case (k, v) if k < 2 => v }.

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

Edit: res2works because of tupling. If an application doesn't type check, the compiler will try wrapping the args in a tuple before failing.

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

But that is tried just for applications; it's not a general conversion, as you discovered. It will not try to upgrade a value Function2[A, B, C]to Function1[(A, B), C].

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