简体   繁体   English

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

[英]Partial function application prematurely runs codeblock when used with underscore

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? 上述两个陈述有什么区别?

First case , 第一种情况

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

According to "Scala Reference" (§6.7), trailing underscore is used in place of the argument list, and expression is converted to 根据“Scala Reference” (§6.7),使用尾随下划线代替参数列表,并将表达式转换为

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

where the first argument of def save is immediately evaluated. 其中def save的第一个参数立即被评估。

The expression e _ is well-formed if e is of method type or if e is a call-by-name parameter. 如果e是方法类型或者e是按名称调用参数,则表达式e _是格式良好的。 If e is a method with parameters, e _ represents e converted to a function type by eta expansion (§6.26.5). 如果e是带参数的方法,则e _表示通过eta扩展转换为函数类型(第6.26.5节)。 If e is a parameterless method or call-by-name parameter of type =>T , e _ represents the function of type () => T , which evaluates e when it is applied to the empty parameterlist (). 如果e是无参数方法或类型为>> T的call-by-name参数,则e _表示type()=> T的函数,它在应用于空参数列表()时计算e。

To make the things work as you expect, some modifications are required: 为了使事情按预期工作,需要进行一些修改:

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)

Second case , 第二种情况

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

According to "Scala Reference" (§6.23), when placeholder is used as a replacement for an argument, the expression is converted to 根据“Scala Reference” (第6.23节),当占位符用作参数的替换时,表达式将转换为

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

The behaviour of call-by-name parameters under eta expansion is currently under review, see this bug . eta扩展下的call-by-name参数的行为目前正在审核中,请参阅此错误 Your code works as you expect (that is, the line save(throw new RuntimeException("boom!")) _ returns a function without throwing the exception) with recent nightly builds of 2.10. 您的代码按预期工作(即行save(throw new RuntimeException("boom!")) _返回一个函数而不抛出异常),最近每晚构建2.10。 Let's see if it stays in until release! 让我们看看它是否会一直存在!

See also this question for a related question on the general case of eta expansion not involving call-by-name. 另请参阅此问题以获取有关eta扩展的一般情况的相关问题,该问题不涉及名称调用。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM