Scala的解释器在解析函数参数(function arguments)时有两种方式:先计算参数表达式的值(reduce the arguments),再应用到函数内部;或者是将未计算的参数表达式直接应用到函数内部。前者叫做传值调用(call-by-value),后者叫做传名调用(call-by-name)。
传值函数和传名函数
object Add {
def addByName(a: Int, b: => Int) = a + b
def addByValue(a: Int, b: Int) = a + b
}
传名函数和传值函数在编译器中区别:
addByName(2, 2 + 2)
->2 + (2 + 2)
->2 + 4
->6
addByValue(2, 2 + 2)
->addByValue(2, 4)
->2 + 4
->6
可以看出,在进入函数内部前,传值调用方式就已经将参数表达式的值计算完毕,而传名调用是在函数内部进行参数表达式的值计算的。
这就造成了一种现象,每次使用传名调用时,解释器都会计算一次表达式的值。对于有副作用(side-effect)的参数来说,这无疑造成了两种调用方式结果的不同。
因此, 在实际的使用中:
传值调用在进入函数体之前就对参数表达式进行了计算,这避免了函数内部多次使用参数时重复计算其值,在一定程度上提高了效率。
但是传名调用的一个优势在于,如果参数在函数体内部没有被使用到,那么它就不用计算参数表达式的值了。在这种情况下,传名调用的效率会高一点。
package Demo
//传名和传值参数
object Demo01 extends App {
def time()={
println("获取时间,单位为毫秒")
System.nanoTime()//时间毫秒
}
//传值调用,直接获取参数名中的值放入主函数中 传值调用(call-by-value)
def delayed(t:Long) ={
println("在delayed方法内")
println("参数为"+t)
}
// 获取时间,单位为毫秒
// 在delayed方法内
// 参数为10874963211520
delayed(time())
//传名调用当遇到参数名的时候 计算参数名中的逻辑 传名调用(call-by-name)
def delayedd(t : =>Long) = {
println("在delayed方法内")
println("参数为" + t)
}
//
// 在delayed方法内
// 获取时间,单位为毫秒
// 参数为11088250581065
delayedd(time())
}
本文深入探讨Scala中的传值(call-by-value)与传名(call-by-name)调用机制,分析两者在参数传递过程中的不同行为及对效率的影响。通过具体示例展示,帮助读者理解何时使用何种调用方式更为合适。
344

被折叠的 条评论
为什么被折叠?



