在此功能中" f" :
def f(x: => Int) : Int = x * x * x //> f: (x: => Int)Int
var y = 0 //> y : Int = 0
f {
y += 1
println("invoked")
y
} //> invoked
//| invoked
//| invoked
//| res0: Int = 6
" F"被调用的次数与" x"相同。参数乘以。
但为什么多次调用函数?
应该" f"不扩展为1 * 1 * 1
而不是1 * 2 * 3
?
答案 0 :(得分:3)
您的x
不是函数,它是一个名称参数,其类型是无参数的方法类型。
无参数方法类型与def x
的含义相同,每次引用时都会对其进行评估。我们所指的是x
而不是x.apply()
或x()
。
每次f
中引用x
时,都会评估您传递给函数f
的表达式。这个表达式是大括号中的整个表达式,一个块表达式。块是一系列语句,后面是结果表达式。
以下是另一种解释:https://stackoverflow.com/a/13337382/1296806
但是,让我们不要把它称为一个功能,即使它的行为类似于一个功能。
以下是规范中使用的语言:
它不是值类型,因为您无法写val i: => Int
。
当他们更改实现时,这是一个大问题,因此您可以将名称arg传递给另一个方法,而无需先对其进行评估。从来没有一个问题可以像这样传递函数值。例如:
scala> def k(y: => Int) = 8
k: (y: => Int)Int
scala> def f(x: => Int) = k(x) // this used to evaluate x
f: (x: => Int)Int
scala> f { println("hi") ; 42 }
res8: Int = 8
一个例外是"保留了名字的行为"传入的x。
由于eta扩张,这对人们很重要:
scala> def k(y: => Int)(z: Int) = y + y + z
k: (y: => Int)(z: Int)Int
scala> def f(x: => Int) = k(x)(_) // normally, evaluate what you can now
f: (x: => Int)Int => Int
scala> val g = f { println("hi") ; 42 }
g: Int => Int = <function1>
scala> g(6)
hi
hi
res11: Int = 90
问题是你期待多少问候?
更多怪癖:
scala> def f(x: => Int) = (1 to 5) foreach (_ => x)
f: (x: => Int)Unit
scala> def g(x: () => Int) = (1 to 5) foreach (_ => x())
g: (x: () => Int)Unit
scala> var y = 0
y: Int = 0
scala> y = 0 ; f { y += 1 ; println("hi") ; y }
hi
hi
hi
hi
hi
y: Int = 5
scala> y = 0 ; g { y += 1 ; println("hi") ; () => y }
hi
y: Int = 1
scala> y = 0 ; g { () => y += 1 ; println("hi") ; y }
hi
hi
hi
hi
hi
y: Int = 5
功能不会导致此问题:
scala> object X { def f(i: Int) = i ; def f(i: => Int) = i+1 }
defined object X
scala> X.f(0)
res12: Int = 0
scala> trait Y { def f(i: Int) = i }
defined trait Y
scala> object X extends Y { def f(i: => Int) = i+1 }
defined object X
scala> X.f(0)
<console>:11: error: ambiguous reference to overloaded definition,
both method f in object X of type (i: => Int)Int
and method f in trait Y of type (i: Int)Int
match argument types (Int)
X.f(0)
^
比较方法类型:
http://www.scala-lang.org/files/archive/spec/2.11/03-types.html#method-types
这不是一个迂腐的区别;无论当前的实现如何,将名字参数视为&#34;真的&#34;可能会令人困惑。一个功能。
答案 1 :(得分:1)
另一种说法已经说过的方法是在f
内部调用函数x
三次。第一次增加y
var并返回1.第二次它再次增加y
返回2,第三次再增加y
并返回3.
如果您只想调用一次,那么您可能需要执行以下操作:
def f(x: => Int) : Int = x * x * x
var y = 0
lazy val xx = {
y += 1
println("invoked")
y
}
f {xx}
这将打印&#39;调用&#39;只有一次并导致返回值为1。
答案 2 :(得分:1)
x:T表示需要T值。
x:=&gt; T表示需要一个T值,但它是按名称调用的。
x:()=&gt; T这意味着需要一个没有给T
的函数然而,这个问题与功能和方法之间的区别无关。
原因是每次尝试使用时都会调用名称调用。
更改为按值 def f(x:Int):Int 调用,它只会调用一次。
答案 3 :(得分:0)
函数f()返回的结果正在改变,因为有一个全局变量随着对该函数的每次后续调用而递增。
f(x:=&gt; Int)中的x
被解释为“返回Int的某个函数”。因此,必须调用3次来评估x*x*x
表达式。每次调用时,都会递增全局变量并返回结果,这是您到达后续三个自然数的方式(因为全局变量初始化为0)。因此1 * 2 * 3.
答案 4 :(得分:0)
因为每次在y
f
递增1