Scala:覆盖集合类型

时间:2011-01-20 11:31:02

标签: scala

class AbstractNode

class Node extends AbstractNode {
  def update() {
    // update something here
  }
}

class AbstractGraph {
  val allNodes = ArrayBuffer[AbstractNode]()
}

class Graph extends AbstractGraph {
  override val allNodes = ArrayBuffer[Node]()
  def updateAll() {
    allNodes.foreach(_.update())
  }
}

上面产生错误:

overriding value allNodes in class AbstractGraph of type scala.collection.mutable.ArrayBuffer[AbstractNode];
value allNodes has incompatible type
override val allNodes = ArrayBuffer[Node]()
             ^

update方法添加到Node的正确方法是什么?这与A Tour of Scala: Explicitly Typed Self References相关吗?

3 个答案:

答案 0 :(得分:7)

因为ArrayBuffer [Node]不是ArrayBuffer [AbstraceNode]的子类型。 它与Variances有关。 在scala中,A是B的子类型,并不意味着S [A]是S [B]的子类型。 它可能导致S [A]亚型S [B]或S [B]子类型S [A]或什么都没有。

例如:

scala> class A
defined class A

scala> class B extends A
defined class B

scala> class S1[+T]
defined class S1

scala> val s11: S1[A] = null.asInstanceOf[S1[B]]
s11: S1[A] = null

scala> val s12: S1[B] = null.asInstanceOf[S1[A]]
<console>:8: error: type mismatch;
 found   : S1[A]
 required: S1[B]
       val s12: S1[B] = null.asInstanceOf[S1[A]]
                                         ^

scala> class S2[-T]
defined class S2

scala> val s21: S2[A] = null.asInstanceOf[S2[B]]
<console>:8: error: type mismatch;
 found   : S2[B]
 required: S2[A]
       val s21: S2[A] = null.asInstanceOf[S2[B]]
                                         ^

scala> val s22: S2[B] = null.asInstanceOf[S2[A]]
s22: S2[B] = null

scala> class S3[T]
defined class S3

scala> val s31: S3[A] = null.asInstanceOf[S3[B]]
<console>:8: error: type mismatch;
 found   : S3[B]
 required: S3[A]
Note: B <: A, but class S3 is invariant in type T.
You may wish to define T as +T instead. (SLS 4.5)
       val s31: S3[A] = null.asInstanceOf[S3[B]]
                                         ^

scala> val s32: S3[B] = null.asInstanceOf[S3[A]]
<console>:8: error: type mismatch;
 found   : S3[A]
 required: S3[B]
Note: A >: B, but class S3 is invariant in type T.
You may wish to define T as -T instead. (SLS 4.5)
       val s32: S3[B] = null.asInstanceOf[S3[A]]

编辑:

class AbstractNode

class Node extends AbstractNode {
  def update() {
    // update something here
  }
}

class AbstractGraph[T <: AbstractNode] {
  val allNodes = ArrayBuffer[T]()
}

class Graph extends AbstractGraph[Node] {
  def updateAll() {
    allNodes.foreach(_.update())
  }
}

答案 1 :(得分:1)

我对Scala也很陌生,但我认为你想要的是abstract types,它们在你链接到的页面上的代码示例中使用。我认为你得到这个错误的原因是你试图将allNodes的类型从AbstractNode缩小到Node。这意味着您的具体实现类型与AbstractGraph不兼容,并且您无法在任何可以使用AbstractGraph的地方使用Graph实例。

如果你想这样做,那么你想使用抽象类型。抽象类型表示存在某些类型,具体实现必须实例化它。在下面的代码中,AbstractGraph说具体实现必须指定类型node,它是AbstractNode的子类型,Graph指定这是类型Node

import scala.collection.mutable.ArrayBuffer

class AbstractNode

class Node extends AbstractNode {
  def update() {
    // update something here
  }
}

class AbstractGraph {
  type node <: AbstractNode
  val allNodes = new ArrayBuffer[node]()
}

class Graph extends AbstractGraph {
  override type node = Node
  def updateAll() {
    allNodes.foreach(_.update())
  }
}

答案 2 :(得分:0)

尝试四处使用不可变集合。它会更容易,因为不可变集合可以是协变的。