Scala中的前向类引用?

时间:2010-10-31 04:51:25

标签: scala

作为Scala的新手,我遇到了一个标准问题:如何以这样的方式定义两个类,我可以创建另一个实例,另一个实例作为成员变量,反过来又指向第一个实例

我想结束   游戏的一个例子      其中有一个经销商类型的成员         它有一个Game类型的成员,实际上是原始的Game实例

因此,在这种情况下,每个实例(Game,Dealer)都有一个成员,这是另一个实例。任何人都可以指导我找到正确的方法吗?

3 个答案:

答案 0 :(得分:8)

如果你真的需要让类不可变,你唯一的选择就是在构造函数中使用name参数,并始终将实例创建为lazy val s:

class Dealer(val name: String, g: => Game) {
  lazy val game = g
  override def toString = "Dealer(name=%s, game=%s)".format(name, game.name)
}

class Game(val name: String, d: => Dealer) {
  lazy val dealer = d
  override def toString = "Game(name=%s, dealer=%s)".format(name, dealer.name)
}

lazy val game: Game = new Game("Doppelkopf", new Dealer("Peter", game))
lazy val dealer: Dealer = new Dealer("Tina", new Game("Poker", dealer))

请注意,您需要在lazy val上使用类型ascription,否则它将无法编译。

答案 1 :(得分:3)

你有两个选择:

  1. 使您的对象可变,然后使用与Java中完全相同的技术。
  2. 让它们不可变,然后放弃双向依赖。
  3. 要了解原因,请考虑(不可变)树之间的以下转换。 这些都定义为每个父节点都包含一个子节点列表,但子节点不知道它们的父节点

    a               (a)
      b               (b)
        c                c
        d     -->       (d) 
      e                e
        f                f
        g                g
    

    具体而言,使用新值克隆节点d。为此,我们还必须克隆所有父节点(显示在括号中)。

    如果节点保留其父级,则必须“更新”c以反映新的b节点,并且必须更新e, f, g以反映新的a 1}}节点。即整个树必须复制!

    通过仅在一个方向上保持关系,从父级到子级,可以在结构的连续版本中重用c, e, f, g。这是一个强大的优化,是编写高效函数算法的关键。

答案 2 :(得分:2)

我认为你在谈论一种“双向”依赖,如果最大的一个实体是不可变的,这很容易做到(如果你想要两者都是不可变的,你应该看到Moviz解决方案)。

在我的例子中,我让Game成为不可变实体。经销商可能不参与游戏。

class Dealer(val name: String){
  var game: Option[Game] = None
}

case class Game(name: String, dealer: Dealer)

// Instanciate the game and the dealer
val olle = new Dealer("Olle")
val ollesGame = Game("Olles Game", olle)
olle.game = Some(ollesGame)