不可变的实例相互引用

时间:2013-10-23 06:15:22

标签: scala

有了这些课程,是否有任何可能的方法来创建一对男朋友/女朋友?也就是说,一个女朋友和男孩的男孩也是她的男朋友。

abstract class Person(val name: String)

case class Girl(name2: String, val boyfriend: Boy) extends Person(name2)

case class Boy(name2: String, val girlfriend: Girl) extends Person(name2)


object Run extends App {
    val alice: Girl = Girl("alice", Boy("Bob",alice))

    // alice.boyfriend.girlfriend is null, not correct
}

1 个答案:

答案 0 :(得分:9)

在没有懒惰评估的情况下,不可能创建自引用不可变结构。但是,Scala中的惰性求值(用lazy vals和call-by-name参数表示)并不像Haskell那样普遍,并且它有其局限性。您的代码可以像这样重写:

Welcome to Scala version 2.10.2 (Java HotSpot(TM) 64-Bit Server VM, Java 1.7.0_25).
Type in expressions to have them evaluated.
Type :help for more information.

scala> :paste
// Entering paste mode (ctrl-D to finish)

abstract class Person(val name: String)

class Girl(val name2: String, _boyfriend: => Boy) extends Person(name2) {
    lazy val boyfriend = _boyfriend
}

class Boy(val name2: String, _girlfriend: => Girl) extends Person(name2) {
    lazy val girlfriend = _girlfriend
}


object Run {
    val alice: Girl = new Girl("alice", new Boy("Bob", alice))
}

// Exiting paste mode, now interpreting.

defined class Person
defined class Girl
defined class Boy
defined module Run

scala> Run.alice.name
res0: String = alice

scala> Run.alice.boyfriend.name
res1: String = Bob

scala> Run.alice.boyfriend.girlfriend.name
res2: String = alice

scala>

你看,这里没有case类 - 你不能按名称调用case类参数,因为它们是作为val公开的,并且vals具有call-by-name类型是没有意义的。此外,我还必须创建额外的lazy val字段,以便不会过早评估call-by-name参数。

这段代码可能会被简化,但它是实现您想要的最简单的方法。