2013-10-23 37 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