Partial function application prematurely runs codeblock when used with underscore

后端 未结 2 1393
终归单人心
终归单人心 2021-01-12 01:05

Given:

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

I can call it with:<

2条回答
  •  情深已故
    2021-01-12 01:29

    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

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

    where the first argument of def save is immediately evaluated.

    The expression e _ is well-formed if e is of method type or if e is a call-by-name parameter. If e is a method with parameters, e _ represents e converted to a function type by eta expansion (§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 ().

    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 = 
    
    scala> f(true)
    running f
    java.lang.RuntimeException: boom!
            at $anonfun$1.apply(: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

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

提交回复
热议问题