据我所知,在Scala中,也可以调用函数
例如,给定以下声明,我们是否知道如何调用该函数?
宣言:
def f (x:Int, y:Int) = x;
Run Code Online (Sandbox Code Playgroud)
呼叫
f (1,2)
f (23+55,5)
f (12+3, 44*11)
Run Code Online (Sandbox Code Playgroud)
请问有什么规定?
dhg*_*dhg 507
您给出的示例仅使用call-by-value,因此我将给出一个新的,更简单的示例,显示差异.
首先,我们假设我们有一个带副作用的函数.此函数打印出一些东西,然后返回一个Int.
def something() = {
println("calling something")
1 // return value
}
Run Code Online (Sandbox Code Playgroud)
现在,我们要定义两个函数,接受Int是完全一样的,只是一个需要在呼叫传值方式(参数参数x: Int),另一个在呼叫按名称样式(x: => Int).
def callByValue(x: Int) = {
println("x1=" + x)
println("x2=" + x)
}
def callByName(x: => Int) = {
println("x1=" + x)
println("x2=" + x)
}
Run Code Online (Sandbox Code Playgroud)
现在当我们用副作用函数调用它们时会发生什么?
scala> callByValue(something())
calling something
x1=1
x2=1
scala> callByName(something())
calling something
x1=1
calling something
x2=1
Run Code Online (Sandbox Code Playgroud)
所以,你可以看到,在呼叫按值版本,传入的函数调用(的副作用something())只发生过一次.但是,在按名称调用版本中,副作用发生了两次.
这是因为call-by-value函数在调用函数之前计算传入的表达式的值,因此每次都访问相同的值.但是,每次访问时,call-by-name函数都会重新计算传入的表达式的值.
小智 50
以下是Martin Odersky的一个例子:
def test (x:Int, y: Int)= x*x
Run Code Online (Sandbox Code Playgroud)
我们想要检查评估策略,并确定在这些条件下哪一个更快(更少步骤):
test (2,3)
Run Code Online (Sandbox Code Playgroud)
按值调用:test(2,3) - > 2*2 - >
按姓名调用:test(2,3) - > 2*2 - > 4
这里以相同的步数达到结果.
test (3+4,8)
Run Code Online (Sandbox Code Playgroud)
按值呼叫:测试(7,8) - > 7*7 - > 49
呼叫按名称:(3 + 4)(3 + 4) - > 7(3 + 4) - > 7*7 - > 49
这里呼叫按价值更快.
test (7,2*4)
Run Code Online (Sandbox Code Playgroud)
按值调用:test(7,8) - > 7*7 - > 49
按姓名呼叫:7*7 - > 49
这里按姓名呼叫更快
test (3+4, 2*4)
Run Code Online (Sandbox Code Playgroud)
按值调用:test(7,2*4) - > test(7,8) - > 7*7 - > 49
按名称调用:(3 + 4)(3 + 4) - > 7(3 + 4) - > 7*7 - > 49
结果在同一步骤内达到.
res*_*a87 15
在您的示例中,所有参数将在函数中调用之前进行评估,因为您只是按值定义它们.如果要按名称定义参数,则应传递代码块:
def f(x: => Int, y:Int) = x
Run Code Online (Sandbox Code Playgroud)
这样,在函数中调用参数之前,x不会对参数进行求值.
为了解释@ Ben在上述评论中的观点,我认为最好将"按名称调用"视为语法糖.解析器只是将表达式包装在匿名函数中,以便在以后使用它们时可以调用它们.
实际上,而不是定义
def callByName(x: => Int) = {
println("x1=" + x)
println("x2=" + x)
}
Run Code Online (Sandbox Code Playgroud)
和运行:
scala> callByName(something())
calling something
x1=1
calling something
x2=1
Run Code Online (Sandbox Code Playgroud)
你也可以这样写:
def callAlsoByName(x: () => Int) = {
println("x1=" + x())
println("x2=" + x())
}
Run Code Online (Sandbox Code Playgroud)
并按如下方式运行它以获得相同的效果:
callAlsoByName(() => {something()})
calling something
x1=1
calling something
x2=1
Run Code Online (Sandbox Code Playgroud)
小智 6
I will try to explain by a simple use case rather than by just providing an example
Imagine you want to build a "nagger app" that will Nag you every time since time last you got nagged.
Examine the following implementations:
object main {
def main(args: Array[String]) {
def onTime(time: Long) {
while(time != time) println("Time to Nag!")
println("no nags for you!")
}
def onRealtime(time: => Long) {
while(time != time) println("Realtime Nagging executed!")
}
onTime(System.nanoTime())
onRealtime(System.nanoTime())
}
}
Run Code Online (Sandbox Code Playgroud)
In the above implementation the nagger will work only when passing by name the reason is that, when passing by value it will re-used and therefore the value will not be re-evaluated while when passing by name the value will be re-evaluated every time the variables is accessed