1

是否有可能通過繼承在Scala中構建不可變列表?我有一個創建MenuBar的基礎特徵。 MenuBar將有標準的標題:文件,編輯,視圖/窗口,幫助等。我希望繼承特性能夠添加子項到菜單標題。我希望菜單動態創建,所以會有一個函數列表,當打開菜單創建子樹時會調用它。由於函數列表在編譯時已知,如果它可能是不可變的列表,它將會很好。構建不可變列表雖然繼承

Scala中是否有任何方式通過構造函數/初始化層次結構創建不可變列表?如果不是在Scala有任何語言提供此功能?

用一個使用可變列表的簡單示例來說明問題。 TrA和TrB的寫互不影響:

trait Base 
{ 
    val list = scala.collection.mutable.LinkedList[String]() 
} 
trait TrA extends Base 
{ 
    list += "A" 
} 
trait TrB extends Base 
{ 
    list += "B" 
} 

val ab = new TrA with TrB {} 

爲列表的內容在編譯時已知反正是有使之成爲VAL不可變列表?當然,任何可變集合都可以通過def調用被公開爲不可變集合。

下面將編譯:

trait Base 
{ val list: List[String] = Nil } 

trait TrA extends Base 
{ val list = "A" :: super.list } 

trait TrB extends Base 
{ val list = "B" :: super.list } 

val ab = new TrA with TrB {} 

但不能沒有拋出一個空的異常被初始化。讓val list懶惰也無濟於事,因此0__解決方案的必要性。

+0

您能否提供一個示例代碼(僞代碼)來顯示您想實現的目標? –

+0

@PetrPudlák希望添加的代碼解釋了問題。 –

回答

4

這與我記得的老問題非常相似;我再也找不到它了,所以我試圖重建該方法:

trait Base { 
    protected def contribute : List[String] = Nil 

    val list = contribute 
} 

trait TrA extends Base { 
    override protected def contribute = "A" :: super.contribute 
} 

trait TrB extends Base { 
    override protected def contribute = "B" :: super.contribute 
} 

val x = new TrA with TrB {} 
x.list // List(B, A) 
val y = new TrB with TrA {} 
y.list // List(A, B) 
+0

聰明。我不知道這是可能的。有趣的是,「with」的順序決定了繼承的順序。我在[本文](http://www.artima.com/weblogs/viewpost.jsp?thread=246488)中找到了一個解釋,其中在_Multiple繼承和方法合作_中他們寫道: _實際上,Scala特徵可以在他們重寫相同的方法,並且組合的順序決定了超級調用的結果模式:這意味着Scala特性基本上具有Python mixins的所有複雜性,我寧願避免這些複雜性._ –

+0

也是維基百科的文章[Multiple inheritance/Diamond problem ](https://en.wikipedia.org/wiki/Multiple_inheritance#The_diamond_problem)討論了Scala如何解決多重繼承問題。 –

+0

我一讀時錯過了,這個解決方案多麼輝煌。至少直到我們得到一個Scala虛擬機,並具有適當的多重繼承。 –

0

我隱藏列表的可變部分,這樣只有Base後人可以添加到它(並沒有別的):

trait Base { 
    private val theList = scala.collection.mutable.LinkedList[String]() 

    protected def add(item: String) { 
    theList += item; 
    } 

    // return only an immutable copy of the list 
    def list: Seq[String] = theList.toSeq; // or .toList, .toSet, etc. 
} 

trait TrA extends Base { 
    add("Apple") 
} 

trait TrB extends Base { 
    add("Orange") 
} 

雖然病態行爲的後代仍然可以再添加一些項目,這是不可能從外部修改列表。也許可以用lazy val list代替def list來獲得一些效率,但是你必須確定它沒有被任何構造函數調用。