2013-10-23 35 views
3

将这些类写入后,是否有任何可能的方法来创建男朋友/女朋友对?也就是说,男朋友和男朋友的男孩也是她的男朋友。互相引用的不可变实例

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 
} 
+2

一个不可变对象表示一个实体在某个时间点的状态。但为了模拟人与人之间的关系,你必须有一种方法来引用一个人,即使它随着时间的推移而变化。所以你需要某种手柄或身份证,即使这个人改变,也保持不变。在某个时间点区分实体和实体状态非常重要。看到这个优秀的演讲很好地说明了这一点:http://www.infoq.com/presentations/Are-We-There-Yet-Rich-Hickey –

回答

9

不可能在没有惰性评估的情况下制作自引用不可变结构。但是,Scala中的懒惰评估(用惰性vals和名称参数表示)并不像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类 - 你不能做的情况下类参数调用按姓名,因为他们被暴露为丘壑,并且它不为丘壑有道理具有按名称类型。此外,我不得不创建额外的lazy val字段,以避免对名称调用参数进行过早评估。

这段代码可能会简化,但它是实现我想得到的最简单的方法。

+0

我真的很喜欢你的解决方案,但我没有尝试过'Run'对象并且在Scala 2.10.2中得到了'正向引用扩展到value alice'的定义。通过制作“懒惰的爱丽丝”来解决问题。为什么会发生? – kisileno

+0

@brainless,你是什么意思,“没有'运行'对象”?见[这个要点](https://gist.github.com/dpx-infinity/7132006),没有任何对象,但定义仍然有效。 –

+0

弗拉基米尔马特维耶夫,我在REPL中试过,并且所有工作都正常。但是,如果我将它插入到现有的scala文件并编译,我有一个错误。也许我的env有一个问题,没关系。谢谢! – kisileno