2011-01-20 106 views
2
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有關嗎?

回答

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

我對Scala很新穎,但我認爲您在這裏想要的是abstract types,它們在您鏈接到的頁面上的代碼示例中使用。我認爲你得到這個錯誤的原因是你想把AbstractNode中的所有節點的類型縮小到節點。這意味着您的具體實現類型與AbstractGraph不兼容,並且您無法在任何可以使用AbstractGraph的地方使用Graph實例。

如果你想這樣做,那麼你想使用抽象類型。抽象類型表示將存在一些類型,具體實現必須實例化它。在下面的代碼中,AbstractGraph表示一個具體的實現必須指定一個node這是AbstractNode的子類型,Graph指定這是Node類型。

+0

謝謝,它幫助!但仍然存在問題。更改`class AbstractNode(val graph:AbstractGraph){graph.allNodes + = this}`。現在彈出另一個奇怪的類型錯誤。有任何想法嗎? – TautrimasPajarskas 2011-01-20 13:09:48

+0

嗯,似乎通過`graph.allNodes + = this.asInstanceOf [AbstractNode.this.graph.Node]`鑄造`幫助。雖然,我不知道這是否是解決問題的正確方法。 – TautrimasPajarskas 2011-01-20 13:40:04

0

嘗試使用各地不可改變的集合。它會容易得多,因爲不可變集合可以是協變的。