在scala lambda函数中使用_

Hug*_*ira 37 scala

任何人都可以解释我为什么这样做:

a.mapValues(_.size)
Run Code Online (Sandbox Code Playgroud)

代替

a.mapValues(x => x.size)
Run Code Online (Sandbox Code Playgroud)

但我不能这样做

a.groupBy(_)
Run Code Online (Sandbox Code Playgroud)

代替

a.groupBy(x => x)
Run Code Online (Sandbox Code Playgroud)

par*_*tic 42

编写时a.groupBy(_),编译器将其理解为匿名函数:

x => a.groupBy(x)
Run Code Online (Sandbox Code Playgroud)

根据Scala规范§6.23,表达式中的下划线占位符将替换为匿名参数.所以:

  • _ + 1 扩大到 x => x + 1
  • f(_) 扩大到 x => f(x)
  • _ 不会自行扩展(占位符不是任何表达式的一部分).

该表达式x => a.groupBy(x)会混淆编译器,因为它无法推断出类型x.如果a是某些类型E元素的集合,那么编译器期望x是类型的函数(E) => K,但是K无法推断类型...

  • @paradigmatic:但是`_`也是一个表达; 它是一个表达式,表示调用方法的值.整个`a.mapValues(_.size)`也是一个表达式.无论哪个块都包含此行.我认为我对它的工作方式有一个直观的大致正确的处理,但是对于Scala编译器到底有多远还有一个很好的定义吗?即为什么它*不会停止将`_`转换为`x => x`,但是*确实*停止将`_.size`转换为`x => s.size`? (2认同)

Dan*_*ral 16

在这里看到它并不容易:

a.groupBy(_)
Run Code Online (Sandbox Code Playgroud)

但是更容易看到这样的事情:

a.mkString("<", _, ">")
Run Code Online (Sandbox Code Playgroud)

我正在部分应用方法/功能.我将它应用于一些参数(第一个和最后一个),并保留第二个参数未应用,所以我得到一个像这样的新函数:

x => a.mkString("<", x, ">")
Run Code Online (Sandbox Code Playgroud)

第一个示例只是一个特殊情况,其中部分应用了唯一参数.但是,在表达式上使用下划线时,它代表匿名函数中的位置参数.

a.mapValues(_.size)
a.mapValues(x => x.size)
Run Code Online (Sandbox Code Playgroud)

很容易混淆,因为它们都会导致匿名功能.实际上,还有第三个下划线用于将方法转换为方法值(也是一个匿名函数),例如:

a.groupBy _
Run Code Online (Sandbox Code Playgroud)