根据我的理解,在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)
请问规则是什么?
当前回答
按值调用是常见的用例,这里有很多答案。
名称调用将一个代码块传递给调用方,每次调用时 调用方访问参数,执行代码块,然后 值被计算。
我将尝试用下面的用例以更简单的方式演示按名调用
示例1:
function下面是按名称调用的简单示例/用例,它将function作为参数并给出所经过的时间。
/**
* Executes some code block and prints to stdout the
time taken to execute the block
for interactive testing and debugging.
*/
def time[T](f: => T): T = {
val start = System.nanoTime()
val ret = f
val end = System.nanoTime()
println(s"Time taken: ${(end - start) / 1000 / 1000} ms")
ret
}
示例2:
apache spark(与scala一起)使用按名称调用的方式使用日志记录,参见日志特性 其中其惰性计算是否日志。isInfoEnabled或否。
protected def logInfo(msg: => String) {
if (log.isInfoEnabled) log.info(msg)
}
其他回答
您给出的示例只使用了按值调用,因此我将给出一个新的、更简单的示例来显示两者的区别。
首先,让我们假设我们有一个带有副作用的函数。这个函数输出一些内容,然后返回一个Int型。
def something() = {
println("calling something")
1 // return value
}
现在我们将定义两个函数,它们接受完全相同的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)
}
当我们用副作用函数调用它们时会发生什么?
scala> callByValue(something())
calling something
x1=1
x2=1
scala> callByName(something())
calling something
x1=1
calling something
x2=1
因此,您可以看到,在按值调用版本中,传入函数调用(something())的副作用只发生了一次。然而,在叫名字的版本中,副作用发生了两次。
这是因为按值调用函数在调用函数之前会计算传入表达式的值,因此每次都会访问相同的值。相反,每次访问传入表达式时,名称调用函数都会重新计算传入表达式的值。
在你的例子中,所有的参数都将在函数中调用之前被求值,因为你只是通过值定义它们。 如果你想通过名称定义参数,你应该传递一个代码块:
def f(x: => Int, y:Int) = x
这样,在函数中调用参数x之前,将不会计算参数x。
这篇小文章也很好地解释了这一点。
我不认为这里所有的答案都是正确的:
在按值调用中,参数只计算一次:
def f(x : Int, y :Int) = x
// following the substitution model
f(12 + 3, 4 * 11)
f(15, 4194304)
15
你可以在上面看到,不管是否需要,所有的参数都会被求值,通常按值调用可以很快,但并不总是像这种情况。
如果评估策略是按名称调用的,那么分解将是:
f(12 + 3, 4 * 11)
12 + 3
15
正如你所看到的,我们从来不需要计算4 * 11,因此节省了一些计算,这有时可能是有益的。
通常,函数的参数是值形参;也就是说,参数的值是在传递给函数之前确定的。但是,如果我们需要编写一个函数,该函数接受一个表达式作为参数,而我们不希望在函数内调用该表达式时才计算该表达式,该怎么办?对于这种情况,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
看到这个:
object NameVsVal extends App {
def mul(x: Int, y: => Int) : Int = {
println("mul")
x * y
}
def add(x: Int, y: Int): Int = {
println("add")
x + y
}
println(mul(3, add(2, 1)))
}
y: => Int是名称调用。通过名称调用传递的是add(2,1)。这将被延迟计算。因此控制台的输出将是“mul”后面跟着“add”,尽管add似乎是先被调用的。按名称调用相当于传递一个函数指针。 现在将y: => Int改为y: Int。控制台将显示“add”后面跟着“mul”!通常的评估方法。