9

Given:

def save(f: => Any)(run:Boolean) { if (run) { println("running f"); f } else println("not running f") } 

I can call it with:

save("test")(true) -> running f
save("test")(false) -> not running f
save(throw new RuntimeException("boom!"))(false) -> not running f
save(throw new RuntimeException("boom!"))(true) -> running f and then exception thrown

Here's the curious behaviour with partial application:

save(throw new RuntimeException("boom!"))(_) -> (Boolean) => Unit = <function1> //as expected
save(throw new RuntimeException("boom!")) _ -> exception thrown

The codeblock is evaluated immediately without being passed in as a function. What is the difference between the above 2 statements?

4

2 回答 2

3

第一种情况

save(throw new RuntimeException("boom!")) _ 

根据“Scala Reference”(第 6.7 节),使用尾随下划线代替参数列表,并将表达式转换为

val f: (Boolean) => Unit = save(throw new RuntimeException("boom!"))

其中第一个参数 ofdef save立即被评估。

如果 e 是方法类型或 e 是按名称调用的参数,则表达式 e _ 是格式良好的。如果 e 是带参数的方法,则 e _ 表示 e 通过 eta 扩展(第 6.26.5 节)转换为函数类型。如果 e 是类型为 =>T 的无参数方法或按名称调用的参数,则 e _ 表示类型为 () => T 的函数,它在应用于空参数列表 () 时计算 e。

为了使事情按您的预期工作,需要进行一些修改:

scala> def save(f:() => Any)(run:Boolean) { if (run) { println("running f"); f() } else println("not running f") }
save: (f: () => Any)(run: Boolean)Unit

scala> val f = save(() => throw new RuntimeException("boom!")) _
f: (Boolean) => Unit = <function1>

scala> f(true)
running f
java.lang.RuntimeException: boom!
        at $anonfun$1.apply(<console>:6)

第二种情况

save(throw new RuntimeException("boom!"))(_)

根据“Scala Reference”(第 6.23 节),当使用占位符代替参数时,表达式将转换为

val f: (Boolean) => Unit = save(throw new RuntimeException("boom!"))(_)
于 2011-02-07T09:31:39.970 回答
0

eta 扩展下的按名称调用参数的行为目前正在审查中,请参阅此错误。您的代码在最近的 2.10 夜间版本中按预期工作(即,该行save(throw new RuntimeException("boom!")) _返回一个函数而不引发异常)。让我们看看它是否会一直保留到发布!

另请参阅此问题以获取有关不涉及按名称调用的 eta 扩展的一般情况的相关问题。

于 2012-05-31T21:42:48.207 回答