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);那么,我们不能用_
替换?
答案 0 :(得分:4)
println(_)
扩展为x => println(x)
,因此{println("hi"); println(_)}
扩展为{println("hi"); x => println(x)}
。因此,当fun{println("hi"); println(_)}
执行时,会执行以下步骤:
评估表达式{{println("hi"); println(_)}}
。这意味着:
println("hi")
,然后x => println(x)
,创建一个将打印其参数的函数对象。func
。 func
将使用10
和20
调用该函数,从而打印这些数字。答案 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