循环定义如下:
def loop : Boolean = loop
当x定义为:def x = loop
时,控制台中会显示“x:Boolean”。
和
当x定义为:val x = loop
时,它会进入无限循环
我知道def正在使用call-name,而val正在使用call by-value。尽管上面定义的关于循环的这一点并不十分清楚。
答案 0 :(得分:4)
def
并未评估作业的右侧。就像
def f(x : Int) = x + 2
没有(在这种情况下逻辑上不能)评估任何事情的f
,只需定义函数f
,意思是def loop : Boolean = loop
和{{} 1}}评估任何东西。您只是定义了要在其他位置执行的函数。
但def x = loop
确实需要评估作业的右侧。所以val
尝试在右侧执行表达式。但是,尝试评估val x = loop
永远不会终止,因为loop
是一个无限循环。
答案 1 :(得分:4)
在这种情况下,按姓名调用或按值调用的区别似乎不太有用,因为您的x
和loop
都不会接受任何参数。
但是val
和def
有两种不同的方式。
第一个区别是:渴望与懒惰。
val
val
的右侧被懒惰地评估,只要
<{1}}已访问。例如:
def
将打印:
def
因为def x = { println("x is evaluated"); 42 }
val y = { println("y is evaluated"); 42 }
x
会立即被评估,而y is evaluated
x is evaluated
只会在我们调用它时进行评估。
另一个区别是计算结果是否被缓存:
y
的值评估,然后缓存x
的值每次评估我们称之为函数这就是为什么
val
将输出:
def
也就是说,def dice = { new scala.util.Random().nextInt(6) + 1 }
val once = { new scala.util.Random().nextInt(6) + 1 }
println(dice + " <-> " + once)
println(dice + " <-> " + once)
println(dice + " <-> " + once)
println(dice + " <-> " + once)
是一个或多或少有用的随机数生成器,它生成值5 <-> 6
4 <-> 6
6 <-> 6
5 <-> 6
,而dice
是一个相当无用的随机值,一旦被修复就会被修复创建
现在,你可以想到一个2x2表在一个维度上具有eager-vs-lazy,而在另一个维度中则是cached-vs-not-cached:
1-6
急切且已缓存 once
lazy 且已缓存(因此已记住val
s)lazy val
懒惰且未缓存 def
是def
,它总是被调用,所以从某种意义上说它们都是类似的 - 渴望和未加工的。在您的代码中,def main
本质上是非终止的尾递归版本
def
但由于loop
是def loop: Boolean = { while (true) {}; true }
,因此是懒惰的,因此在定义时不会评估右侧。
如果您现在定义
loop
仍然没有发生任何事情,因为def
也是懒惰的,所以再次没有评估右侧。
但是如果你定义
def x = loop
然后x
是val x = loop
,因此其右侧会被急切地评估。在定义的右侧,有一个x
的调用。现在访问val
,因为它是loop
,它现在评估它的主体,并进入无限循环。