通过继承构建不可变列表

时间:2012-09-24 19:01:38

标签: scala immutability multiple-inheritance scala-collections

是否可以通过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__的解决方案。

2 个答案:

答案 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以获得一些效率,但你必须确保它不会在任何构造函数中被调用。