作为Scala的新手,我遇到了一个标准问题:如何以这样的方式定义两个类,我可以创建另一个实例,另一个实例作为成员变量,反过来又指向第一个实例
我想结束 游戏的一个例子 其中有一个经销商类型的成员 它有一个Game类型的成员,实际上是原始的Game实例
因此,在这种情况下,每个实例(Game,Dealer)都有一个成员,这是另一个实例。任何人都可以指导我找到正确的方法吗?
答案 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)
你有两个选择:
要了解原因,请考虑(不可变)树之间的以下转换。 这些都定义为每个父节点都包含一个子节点列表,但子节点不知道它们的父节点:
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)