2017-07-27 67 views
1

在一個小型圖書館,我會盡力去寫,最終面向用戶的部分看起來像這樣:參考容器容器中的項目

case class Box(is: Item*) 
case class Item(data: Int) 

Box(Item(0), Item(1)) 

理想的,但是,每一個項目都應該知道其中它是:

case class Item(data: Int, box: Box) 

有沒有什麼辦法建立這種雙向連接與不可變案例類?我試圖避免這樣的事情...

val box = Box() 
val i = Item(0, box) 
box.add(i) // requires var in Box :(

或本:

val i = Item(0, None) // requires Option :(
val box = Box(i) 
i.box = Some(box) // requires var in Item :(

...用懶惰,implicits但未能拿出一個解決方案。它有可能嗎?

從以下問題中,我瞭解到名稱+懶惰可能有用,但仍然需要明確傳遞框:[Scala: circular references in immutable data types?。我們的目標是使最終用戶面向部分簡單/苗條越好,在幕後根據需要,可以使用:)

回答

0

你可以做這樣的事情是大的魔力:

case class Box(is: (Box => Item)*) { 
    lazy val items = is.map(_(this)) 
} 
class Item(val data: Int, val box: Box) 
object Item { 
    def apply(data: Int)(box: Box): Item = new Item(data, box) 
} 

val b = new Box(Item(0), Item(1)) 

缺點Box構造函數有點奇怪,Item不能再是一個case類,因爲它依賴於改變Item對象的方法apply。但是,這會爲您創建用於創建對象的完全相同的語法,並創建循環引用。

+1

一個問題是「盒(Item(0))== Box(Item(0))== false'。另一個是'Box(Item(0))。toString == Box(WrappedArray())''。不適用也不起作用。您必須取消案例類,並明確實施所有的好東西才能使其發揮作用。 – Dima

+0

我同意,這種方法有很多缺點。似乎只是在'Item'中使用'var'並不會那麼糟糕,相對而言。但原始問題具體問到如何不斷改進。 –

+0

不使用大小寫類可能是一個好主意(具有var的case類無論如何都會遇到麻煩)。 – Dima