Scala 为什么可以';我不能在代码块中递归地定义一个变量吗?
为什么不能在代码块中递归定义变量Scala 为什么可以';我不能在代码块中递归地定义一个变量吗?,scala,recursion,Scala,Recursion,为什么不能在代码块中递归定义变量 scala> { | val test: Stream[Int] = 1 #:: test | } <console>:9: error: forward reference extends over definition of value test val test: Stream[Int] = 1 #:: test
scala> {
| val test: Stream[Int] = 1 #:: test
| }
<console>:9: error: forward reference extends over definition of value test
val test: Stream[Int] = 1 #:: test
^
scala> val test: Stream[Int] = 1 #:: test
test: Stream[Int] = Stream(1, ?)
scala>{
|val测试:流[Int]=1#:::测试
| }
:9:错误:正向引用扩展到值测试的定义上
val测试:流[Int]=1#:::测试
^
scala>val测试:流[Int]=1#:::测试
测试:流[Int]=流(1,?)
lazy
关键字解决了这个问题,但我不理解为什么它在没有代码块的情况下工作,但在代码块中抛出编译错误。此行为的原因取决于不同的val初始化时间。如果直接在REPL中键入val x=5
,x
将成为对象的成员,可以使用默认值(null、0、0.0、false)初始化该对象的值。相反,块中的值不能由默认值初始化
这会导致不同的行为:
scala> class X { val x = y+1; val y = 10 }
defined class X
scala> (new X).x
res17: Int = 1
scala> { val x = y+1; val y = 10; x } // compiles only with 2.9.0
res20: Int = 11
在Scala 2.10中,最后一个示例不再编译。在2.9.0中,编译器对值重新排序,以使其进行编译。有一个描述不同初始化时间的函数。请注意,在REPL
scala> val something = "a value"
评估结果大致如下所示:
object REPL$1 {
val something = "a value"
}
import REPL$1._
因此,任何val
(或def
等)都是内部REPL helper对象的成员
现在关键是类(和对象)允许对其成员进行正向引用:
object ForwardTest {
def x = y // val x would also compile but with a more confusing result
val y = 2
}
ForwardTest.x == 2
对于块内的val
s,情况并非如此。在块中,所有内容都必须按线性顺序定义。因此,val
s不再是成员,而是普通变量(或值)。以下内容也不会编译:
def plainMethod = { // could as well be a simple block
def x = y
val y = 2
x
}
<console>: error: forward reference extends over definition of value y
def x = y
^
def plainMethod={//也可以是一个简单的块
def x=y
val y=2
x
}
:错误:正向引用扩展到值y的定义上
def x=y
^
造成差异的不是递归。不同之处在于类和对象允许向前引用,而块不允许向前引用。我将在编写时添加这一点:
object O {
val x = y
val y = 0
}
你实际上写的是:
object O {
val x = this.y
val y = 0
}
当你在一个定义中声明这个东西时,这个就是你所缺少的。我想补充一点,基于Eclipse的Scala IDE(v4.0.0)中的Scala工作表在这方面的行为与人们可能期望的REPL不同(例如,说“工作表就像类固醇上的REPL会话”),但与一个长方法的定义类似:即,工作表中的前向引用val定义(包括递归val定义)必须成为某个对象或类的成员。最后一个示例不编译。(这当然是问题的全部。)@Debilski:你说得对,2.10版本不再编译了。我使用了2.9.0来编译它,正如bug报告中提到的。我使用的是2.9.1-1。所以它一定是在两者之间被改变了。