首先解释下call by name 的作用:
all by name : 为了避免在调用时用() => 符号,以为这有点丑陋: Omit the (), but not the
=> in the parameter declaration
比如没有call by name
def runInThread(block: () => Unit) {
new Thread {
override def run() { block() }
}.start()
}
这样调用的时候是这样的 runInThread { () => println("Hi"); Thread.sleep(10000); println("Bye") } 必须要有() =>,丑陋
应用call by name,就可以这样声明函数的参数
def runInThread(block: => Unit) {
new Thread {
override def run() { block }
}.start()
}
调用的时候就变的简单优雅:
runInThread { println("Hi"); Thread.sleep(10000); println("Bye") }
两者之间的比较:
Call by name :传给函数/方法M的参数是另外一个参数函数,该参数函数在函数体内调用时执行
call by value : 传给函数的参数是个值,如果是个表达式或者是另外一个参数函数,则要先计算出表达式的值或者是要先得到参数函数执行后的返回值
《Programming in Scala, 2nd Edition》在 9.5 By-name parameters 一节出给出一个例子解释
代码如下:
object bynameparameters extends App {
var assertionsEnabled = false
//Call by name
def byNameAssert(predicate: => Boolean) =
if (assertionsEnabled && !predicate)
throw new AssertionError
//call by value
def boolAssert(predicate: Boolean) =
if (assertionsEnabled && !predicate)
throw new AssertionError
//boolAssert(3 /0 == 0) // java.lang.ArithmeticException: / by zero
byNameAssert(3 / 0 == 0) //will not yield an exception:
}
当执行boolAssert(3 /0 == 0) 时,会先算3 /0 == 0表达式,于是抛出异常
但是执行byNameAssert(3 / 0 == 0),3 / 0 == 0,会隐式转换成一个函数predicate给byNameAssert,因为assertionsEnabled = false,所以在if语句判断中永远不会执行predicate方法,所以不会产生异常
另外在stackoverflowe 上有篇关于“call by name“和 “call by value”的解释不错,可以参考