匿名函数作为参数

时间:2016-05-28 15:15:57

标签: scala

def fun(f: Int => Unit) {
  f(10)
  f(20)
}
println("method 1 call:")
fun(i => {println("hi"); println(i)})
println("method 2 call:")
fun{println("hi"); println(_)}

输出结果为:

E:\test\scala>scala i.scala
method 1 call:
hi
10
hi
20
method 2 call:
hi
10
20

我认为i => {println("hi"); println(i)}println("hi"); println(_)是相同的。因为我们有一个参数而且参数只使用一次,所以我们可以使用_来简化代码。

然后,为什么方法2只打印" hi"一旦? (这是否意味着:如果我想使用_来简化调用,=>右边的内容可以有一个表达式,如果有多个表达式,例如println("嗨"); println(i);那么,我们不能用_替换?

2 个答案:

答案 0 :(得分:4)

println(_)扩展为x => println(x),因此{println("hi"); println(_)}扩展为{println("hi"); x => println(x)}。因此,当fun{println("hi"); println(_)}执行时,会执行以下步骤:

  1. 评估表达式{{println("hi"); println(_)}}。这意味着:

      评估
    1. println("hi"),然后
    2. 评估
    3. x => println(x),创建一个将打印其参数的函数对象。
    4. 这样创建的函数对象是表达式的结果。
  2. 使用创建的函数对象作为参数调用方法funcfunc将使用1020调用该函数,从而打印这些数字。

答案 1 :(得分:1)

首先,您必须知道在scala中{ block; of; code }是一个表达式,它计算出它内部的最后一个表达式求值的内容。

当你说:

fun(i => { println("hi"); println(i) })

你创建了一个匿名函数,该函数包含2个表达式,两个表达式都返回(),并且在调用函数时评估它们,所有内容都按预期进行评估。

但是当你说

fun({println("hi"); println(_)})

你传入一个块,而不是一个匿名函数。正如sepp2k解释的那样,这扩展到了

{ println("hi"); x => println(x) }

因此,您将一个块传递给fun,此块在传递之前正在进行评估。所以首先println("hi")发生,它只被打印一次,因为块被评估一次,然后评估这个x => println(x),它是一个函数Int => Unit,用于打印它的参数。这个,只有这个(作为最后一个表达式传递给fun。这就是为什么每次调用fun时它只会打印两次参数。

要进一步了解块如何工作,您可以查看这个在块中执行更多操作的示例

fun {
  println("building the function")
  val uuidOfThisFunction = UUID.randomUUID
  x => println(s"$uuidOfThisFunction, $x")
}

所以这个块准备一个函数,通过闭包给它一些额外的上下文。对于fun发生的两次通话,此uuid将保持不变。

building the function
86e74b5e-83b5-41f3-a71c-eeafcd1db2a0, 10
86e74b5e-83b5-41f3-a71c-eeafcd1db2a0, 20

看起来更像你第一次打电话的例子是

fun(
  x => {
    println("calling the function")
    val uuidOfThisCall = UUID.randomUUID
    println(s"$uuidOfThisCall, $x")
  }
)

每次调用f时,块都会进行评估。

calling the function
d3c9ff0a-84b4-47a3-8153-c002fa16d6c2, 10
calling the function
a0b1aa5b-c0ea-4047-858b-9db3d43d4983, 20