scala:创建对象时的循环引用? [英] scala: circular reference while creating object?

查看:114
本文介绍了scala:创建对象时的循环引用?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我不小心遇到了这样的情况(示例被简化以隔离问题):

I accidentally ran into a situation like this (the example is simplified to isolate the problem):

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)
  }
}

有人想猜猜输出吗?:-)

Anyone would like to guess the output? :-)

e1: First   e1.other: Second
e2: Second   e2.other: null

输出有点意思.显然,在创建第二个对象时,第一个对象尚不存在,因此分配了 null.问题是……太不对劲了!我花了几个小时才找到这个.编译器不应该说明一下吗?有趣的是,当我尝试将它作为 Scala 脚本运行时(相同的代码,减去 object Maindef main 行,并关闭 }s),我得到了一个无限序列(不是真的无限-在某些时候列表停止了,我猜是由于对异常跟踪深度的一些限制,或其他)像这样的异常:

The output makes kind of sense. Apparently at the time the Second object is created, the First one does not yet exist, therefore null is assigned. The problem is... It's so wrong! It took me a couple of hours to track this one down. Shouldn't the compiler tell something about this? Interestingly, when I tried to run the thing as a Scala script (the same code, minus object Main and def main lines, and closing }s), I got an infinite sequence (not really infinite - at some point the list stops, I guess due to some limitation on the depth of Exception traces, or something) of exceptions like this:

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)
...

我很想在运行时得到一些至少能提供信息的东西......

I'd love to get something at least as informative during runtime...

好的.我结束了我的咆哮.现在我想我应该问点什么.:)那么,你能推荐一个指向另一个的案例对象的好设计吗?顺便说一下,在我的实际情况中,有几个对象以循环方式指向下一个和前一个实例(最后一个指向第一个,反之亦然).

Ok. I finished my rant. Now I guess I should ask something. :) So, could you recommend any nice design for case objects pointing one to another? By the way, in my real situation there are several objects pointing to the next and previous instances in circular way (the last one points to the first one and vice versa).

使用 Scala 2.8.1-final

Using Scala 2.8.1-final

我找到了解决主要问题的方法:

I found a solution for my main problem:

abstract class Element {
  val other: Element
}
case object First extends Element {
  val other = Second
}
case object Second extends Element {
  val other = First
}

这似乎适用于编译版本(但不适用于 Scala 脚本!).任何人都可以对这里发生的事情有所了解吗?

This seems to work in compiled version (but not as a Scala script!). Could anyone shed some light on what's going on here?

这作为脚本工作(同样的事情,只是使用 defs):

This works as a script (the same thing, just using defs):

abstract class Element { def other: Element }
case object First extends Element { def other = Second }
case object Second extends Element { def other = First }

推荐答案

通常的方法是这样的(改变了嵌套以便你可以将其粘贴到 REPL 中):

The usual way is like this (changed nesting so you can paste it into the 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 中以备将来参考.

That is, take a by-name parameter and stick it into a lazy val for future reference.

您找到的修复程序有效,因为对象本身是惰性的,您可以引用它们,但在您使用它们之前它们不会被创建.因此,一个对象可以自由地将自己指向另一个对象,而无需另一个对象已经初始化.

The fix you found works because objects are themselves lazy in that you can refer to them but they don't get created until you use them. Thus, one object is free to point itself at the other without requiring that the other one has been initialized already.

这篇关于scala:创建对象时的循环引用?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆