斯卡拉:重写集合类型
问题描述:
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
方法节点的正确方法是什么?这与A Tour of Scala: Explicitly Typed Self References有关吗?
答
因为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())
}
}
答
我对Scala很新颖,但我认为您在这里想要的是abstract types,它们在您链接到的页面上的代码示例中使用。我认为你得到这个错误的原因是你想把AbstractNode中的所有节点的类型缩小到节点。这意味着您的具体实现类型与AbstractGraph不兼容,并且您无法在任何可以使用AbstractGraph的地方使用Graph实例。
如果你想这样做,那么你想使用抽象类型。抽象类型表示将存在一些类型,具体实现必须实例化它。在下面的代码中,AbstractGraph表示一个具体的实现必须指定一个node
这是AbstractNode的子类型,Graph指定这是Node
类型。
答
尝试使用各地不可改变的集合。它会容易得多,因为不可变集合可以是协变的。
谢谢,它帮助!但仍然存在问题。更改`class AbstractNode(val graph:AbstractGraph){graph.allNodes + = this}`。现在弹出另一个奇怪的类型错误。有任何想法吗? – TautrimasPajarskas 2011-01-20 13:09:48
嗯,似乎通过`graph.allNodes + = this.asInstanceOf [AbstractNode.this.graph.Node]`铸造`帮助。虽然,我不知道这是否是解决问题的正确方法。 – TautrimasPajarskas 2011-01-20 13:40:04