当与下划线一起使用时,部分函数应用程序会过早地运行代码块

ssa*_*anj 9 scala currying partialfunction eta-expansion

鉴于:

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

我可以用它来调用它:

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
Run Code Online (Sandbox Code Playgroud)

这是部分应用的奇怪行为:

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

立即评估代码块而不作为函数传递.上述两个陈述有什么区别?

Vas*_*iuk 3

第一个案例

\n\n
save(throw new RuntimeException("boom!")) _ \n
Run Code Online (Sandbox Code Playgroud)\n\n

根据“Scala Reference”(\xc2\xa76.7),使用尾随下划线代替参数列表,并将表达式转换为

\n\n
val f: (Boolean) => Unit = save(throw new RuntimeException("boom!"))\n
Run Code Online (Sandbox Code Playgroud)\n\n

其中 的第一个参数def save立即被求值。

\n\n
\n

如果 e\n 是方法类型或者 e 是按名称调用参数,则表达式 e _ 格式良好。如果 e 是带参数的方法,则 e _ 表示通过 eta 扩展转换为函数类型 (\xc2\xa76.26.5)。如果 e 是类型为 =>T 的无参数方法或按名称调用参数,则 e _ 表示类型为 () => T 的函数,该函数在将 e 应用于\n 时对 e 求值\n n 空参数列表()。

\n
\n\n

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

\n\n
scala> def save(f:() => Any)(run:Boolean) { if (run) { println("running f"); f() } else println("not running f") }\nsave: (f: () => Any)(run: Boolean)Unit\n\nscala> val f = save(() => throw new RuntimeException("boom!")) _\nf: (Boolean) => Unit = <function1>\n\nscala> f(true)\nrunning f\njava.lang.RuntimeException: boom!\n        at $anonfun$1.apply(<console>:6)\n
Run Code Online (Sandbox Code Playgroud)\n\n

第二个案例

\n\n
save(throw new RuntimeException("boom!"))(_)\n
Run Code Online (Sandbox Code Playgroud)\n\n

根据“Scala Reference” (\xc2\xa76.23),当占位符用作参数的替换时,表达式将转换为

\n\n
val f: (Boolean) => Unit = save(throw new RuntimeException("boom!"))(_)\n
Run Code Online (Sandbox Code Playgroud)\n