根据我的理解,在Scala中,函数也可以被调用
传递或 的名字
例如,给定以下声明,我们是否知道函数将如何被调用?
声明:
def f (x:Int, y:Int) = x;
Call
f (1,2)
f (23+55,5)
f (12+3, 44*11)
请问规则是什么?
根据我的理解,在Scala中,函数也可以被调用
传递或 的名字
例如,给定以下声明,我们是否知道函数将如何被调用?
声明:
def f (x:Int, y:Int) = x;
Call
f (1,2)
f (23+55,5)
f (12+3, 44*11)
请问规则是什么?
当前回答
下面是Martin Odersky的一个例子:
def test (x:Int, y: Int)= x*x
我们希望检查评估策略,并确定在这些条件下哪个更快(步骤更少):
test (2,3)
按值调用:test(2,3) -> 2*2 -> 4 按名称调用:test(2,3) -> 2*2 -> 4 这里的结果是用相同数量的步骤达到的。
test (3+4,8)
按值调用:test (7,8) -> 7*7 -> 49 按名字呼叫:(3+4)(3+4)-> 7(3+4)-> 7*7 ->49 这里按值调用更快。
test (7,2*4)
按值调用:test(7,8) -> 7*7 -> 49 按名字呼叫:7 * 7 -> 49 在这里叫名字比较快
test (3+4, 2*4)
按值调用:test(7,2*4) -> test(7,8) -> 7*7 -> 49 按名字呼叫:(3+4)(3+4)-> 7(3+4)-> 7*7 -> 49 结果是在相同的步骤中达到的。
其他回答
下面是Martin Odersky的一个例子:
def test (x:Int, y: Int)= x*x
我们希望检查评估策略,并确定在这些条件下哪个更快(步骤更少):
test (2,3)
按值调用:test(2,3) -> 2*2 -> 4 按名称调用:test(2,3) -> 2*2 -> 4 这里的结果是用相同数量的步骤达到的。
test (3+4,8)
按值调用:test (7,8) -> 7*7 -> 49 按名字呼叫:(3+4)(3+4)-> 7(3+4)-> 7*7 ->49 这里按值调用更快。
test (7,2*4)
按值调用:test(7,8) -> 7*7 -> 49 按名字呼叫:7 * 7 -> 49 在这里叫名字比较快
test (3+4, 2*4)
按值调用:test(7,2*4) -> test(7,8) -> 7*7 -> 49 按名字呼叫:(3+4)(3+4)-> 7(3+4)-> 7*7 -> 49 结果是在相同的步骤中达到的。
在你的例子中,所有的参数都将在函数中调用之前被求值,因为你只是通过值定义它们。 如果你想通过名称定义参数,你应该传递一个代码块:
def f(x: => Int, y:Int) = x
这样,在函数中调用参数x之前,将不会计算参数x。
这篇小文章也很好地解释了这一点。
通常,函数的参数是值形参;也就是说,参数的值是在传递给函数之前确定的。但是,如果我们需要编写一个函数,该函数接受一个表达式作为参数,而我们不希望在函数内调用该表达式时才计算该表达式,该怎么办?对于这种情况,Scala提供了名称调用参数。
名称调用机制将一个代码块传递给被调用方,每次被调用方访问参数时,都会执行该代码块并计算该值。
object Test {
def main(args: Array[String]) {
delayed(time());
}
def time() = {
println("Getting time in nano seconds")
System.nanoTime
}
def delayed( t: => Long ) = {
println("In delayed method")
println("Param: " + t)
t
}
}
1. C:/>scalac Test.scala 2. scala Test 3. In delayed method 4. Getting time in nano seconds 5. Param: 81303808765843 6. Getting time in nano seconds
Scala变量计算在better https://sudarshankasar.medium.com/evaluation-rules-in-scala-1ed988776ae8中解释
def main(args: Array[String]): Unit = { //valVarDeclaration 2 println("****starting the app***") // ****starting the app*** val defVarDeclarationCall1 = defVarDeclaration // defVarDeclaration 1 val defVarDeclarationCall2 = defVarDeclaration // defVarDeclaration 1 val valVarDeclarationCall1 = valVarDeclaration // val valVarDeclarationCall2 = valVarDeclaration // val lazyValVarDeclarationCall1 = lazyValVarDeclaration // lazyValVarDeclaration 3 val lazyValVarDeclarationCall2 = lazyValVarDeclaration // callByValue({ println("passing the value "+ 10) 10 }) // passing the value 10 // call by value example // 10 callByName({ println("passing the value "+ 20) 20 }) // call by name example // passing the value 20 // 20 } def defVarDeclaration = { println("defVarDeclaration " + 1) 1 } val valVarDeclaration = { println("valVarDeclaration " + 2) 2 } lazy val lazyValVarDeclaration = { println("lazyValVarDeclaration " + 3) 3 } def callByValue(x: Int): Unit = { println("call by value example ") println(x) } def callByName(x: => Int): Unit = { println("call by name example ") println(x) }
正如我假设的那样,上面讨论的按值调用函数只是将值传递给函数。根据Martin Odersky的说法,这是Scala遵循的一种评估策略,在函数评估中扮演着重要的角色。但是,让叫名字变得简单。这就像将函数作为参数传递给方法(也称为高阶函数)。当方法访问传递参数的值时,它调用传递函数的实现。如下:
根据@dhg示例,首先创建方法如下:
def something() = {
println("calling something")
1 // return value
}
这个函数包含一个println语句并返回一个整数值。创建函数,其参数为call-by-name:
def callByName(x: => Int) = {
println("x1=" + x)
println("x2=" + x)
}
此函数参数定义了一个匿名函数,返回一个整数值。在这个x中包含一个函数的定义,它传递0个参数,但返回int值,我们的something函数包含相同的签名。调用函数时,将函数作为参数传递给callByName。但在按值调用的情况下,它只将整数值传递给函数。我们将函数调用如下:
scala> callByName(something())
calling something
x1=1
calling something
x2=1
在这里,我们的something方法调用了两次,因为当我们在callByName方法中访问x的值时,它调用了something方法的定义。