使用下划线构造lambda表达式

chi*_*ity 5 lambda scala anonymous-function

这段代码

(1 to 30).foreach { x =>
  println(x)
  println
}
Run Code Online (Sandbox Code Playgroud)

做什么我期望:它打印每一个130,用空格穿插.我很清楚这里发生了什么,我想:我正在传递一个首先打印其参数的匿名函数,然后打印一个空白行.

我不明白的是为什么不这样做:

(1 to 30).foreach {
  println _
  println
}
Run Code Online (Sandbox Code Playgroud)

它看起来相当于我.下划线应代表该函数的第一个也是唯一的参数; 并且该函数打印其参数,然后打印一个空行.但是当我运行第二个版本时,我没有得到空白行.

是什么导致这种差异?

mik*_*łak 5

第一个变体很简单:

  1. 在第一行中,申请printlnx.
  2. 在第二行中,应用无参数println(这将打印额外的换行符).

使用第二个变体,您可以有效地告诉Scala执行此操作:

  1. 在第一行中,定义一个函数对象println().随后,对这个新创建的对象不执行任何操作.
  2. 在第二行中,应用于println参数(序列的元素).

混淆源于假设println(x)并且println _是等价的.它们是不同的.funcId _语法的基础上定义新的功能funcId,它是不一样的,调用函数使用"强调的说法"符号.


Den*_*nis 5

这里发生了很多事情。

首先,所有参数占位符语法只能在 lambda 定义的外括号内使用。它不能在您在 lambda 定义中执行的方法调用的括号内使用。

这里有一个例子来证明这一点。

val a = (1 to 10).map(_ + 1)
Run Code Online (Sandbox Code Playgroud)

这将起作用。

val b = (1 to 10).map(math.sin(_ + 1))
Run Code Online (Sandbox Code Playgroud)

这是行不通的。

因此,您的代码根本不使用参数占位符语法。相反,它使用部分应用函数。

例如

(1 to 10).foreach(println _)
Run Code Online (Sandbox Code Playgroud)

在功能上等于

val a = println (_ : Int)
(1 to 10).foreach(a)
Run Code Online (Sandbox Code Playgroud)

此外,当在 lambda 表达式中使用方法名称时,可以省略下划线。Scala 仍然会生成部分应用的方法。

所以

(1 to 10).foreach(println)
Run Code Online (Sandbox Code Playgroud)

等于

(1 to 10).foreach(println _)
Run Code Online (Sandbox Code Playgroud)

因此你的代码等于

val a = println (_ : Int)
  (1 to 10).foreach{
    a
    a
  }
Run Code Online (Sandbox Code Playgroud)

并且因为 {aa} 返回 a,所以它等于

val a = println (_ : Int)
(1 to 10).foreach(a)
Run Code Online (Sandbox Code Playgroud)