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来获得一些效率,但是你必须确定它没有被任何构造函数调用。