结论:
①使用 :=>
把函数参数声明成为call-by-name的
②Scala的解释器在解析函数参数(function arguments)时有两种方式:
- 传值调用(call-by-value):先计算参数表达式的值,再应用到函数内部;
- 传名调用(call-by-name):将未计算的参数表达式直接应用到函数内部
③每次使用传名调用时,解释器都会计算一次表达式的值。而使用传值调用时,表达式的值会提前计算好,只计算一次表达式的值。
1. 例子
object testCallByName {
def main(args: Array[String]): Unit = {
callByName(something())
}
def something() = {
println("calling something")
1 // return value
}
def callByValue(x: Int) = {
println("x1=" + x)
println("x2=" + x)
}
def callByName(x: => Int) = {
println("x1=" + x)
println("x2=" + x)
}
}
运行结果如下:
当调用callByName方法时:

当调用callByValue方法时:

2. 两者对比
call-by-value在进入函数体之前就对参数表达式进行了计算,这避免了函数内部多次使用参数时重复计算其值,在一定程度上提高了效率。
但是call-by-name的一个优势在于,如果参数在函数体内部没有被使用到,那么它就不用计算参数表达式的值了。在这种情况下,call-by-name的效率会高一点。
object notUse {
def main(args: Array[String]) = {
val flag = true
println(useOrNotUse(flag, 1, getANumber()))
}
def getANumber() = {
println("getANumber调用了")
2 // return value
}
def useOrNotUse(flag: Boolean, x: Int, y: => Int) = {
if (flag) {
x
}
else {
x + y
}
}
}
方法useOrNotUse的第三个参数y被定义为call-by-name的。当flag=true时,方法useOrNotUse不需要使用到y。所以不会调用getANumber()方法。结果如下:

当我们把flag设置为false时,需要用到y,此时才会调用getANumber()方法。此时运行结果如下:

网友评论