我不小心碰到了这样的情况(这个例子被简化以隔离问题):
abstract class Element(val other: Element)
case object First extends Element(Second)
case object Second extends Element(First)
object Main {
def main(arguments: Array[String]) {
val e1 = First
val e2 = Second
println("e1: "+e1+" e1.other: "+e1.other)
println("e2: "+e2+" e2.other: "+e2.other)
}
}
有人想猜测输出吗? : - )
e1: First e1.other: Second
e2: Second e2.other: null
输出很有意义。显然,在创建第二个对象时,第一个对象尚不存在,因此分配了null
。问题是......这是错的!我花了几个小时跟踪这个。编译器不应该说出这个吗?
有趣的是,当我尝试将事物作为Scala脚本运行时(相同的代码,减去object Main
和def main
行,并关闭}
s),我得到了一个无限的序列(不是真的无限 - 在某些时候列表停止,我想是由于某些例外情况的异常跟踪或某事的深度有限制:
vilius@blackone:~$ scala 1.scala
...
at Main$$anon$1.Main$$anon$$Second(1.scala:4)
at Main$$anon$1$First$.<init>(1.scala:3)
at Main$$anon$1.Main$$anon$$First(1.scala:3)
at Main$$anon$1$Second$.<init>(1.scala:4)
at Main$$anon$1.Main$$anon$$Second(1.scala:4)
at Main$$anon$1$First$.<init>(1.scala:3)
...
我希望在运行时至少提供一些信息......
确定。我完成了我的咆哮。现在我想我应该问一些事情。 :) 那么,你能推荐一个很好的设计用于指向彼此的案例对象吗?顺便说一句,在我的实际情况中,有几个对象以循环方式指向下一个和前一个实例(最后一个指向第一个实例,反之亦然)。
使用Scala 2.8.1-final
修改 我找到了解决我主要问题的方法:
abstract class Element {
val other: Element
}
case object First extends Element {
val other = Second
}
case object Second extends Element {
val other = First
}
这似乎在编译版本中有效(但不是作为Scala脚本!)。有人能说清楚这里发生了什么吗?
EDIT2:这是一个脚本(同样的事情,仅使用def
s):
abstract class Element { def other: Element }
case object First extends Element { def other = Second }
case object Second extends Element { def other = First }
答案 0 :(得分:9)
通常的方法是这样的(更改嵌套,以便将其粘贴到REPL中):
object Main{
abstract class Element(other0: => Element) {
lazy val other = other0
}
case object First extends Element(Second)
case object Second extends Element(First)
def main(arguments: Array[String]) {
val e1 = First
val e2 = Second
println("e1: "+e1+" e1.other: "+e1.other)
println("e2: "+e2+" e2.other: "+e2.other)
}
}
即,取一个名字参数并将其粘贴到一个懒惰的val中以供将来参考。
编辑:您找到的修复程序有效,因为对象本身很懒,您可以引用它们,但在使用它们之前不会创建它们。因此,一个对象可以自由地指向另一个对象而不需要已经初始化另一个对象。