是否可以通过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 {}
由于List的内容在编译时是已知的,无论如何都要使它成为 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 {}
但是如果不抛出null异常就无法初始化它。使val列表懒惰也无济于事,因此需要0__的解决方案。
答案 0 :(得分: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)
答案 1 :(得分: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")
}
虽然行为不端的后代仍然可以在以后添加一些项目,但是无法从外部修改列表。也许有可能用def list
取代lazy val list
以获得一些效率,但你必须确保它不会在任何构造函数中被调用。