2011-04-01 40 views
7

Scala語言規範版本2.8的第4.6.2節描述了重複參數和表示:在Scala中覆蓋重複的類參數?

的參數部分的最後值參數可以由「*」,例如爲後綴(...,x:T *)。這樣一個類型的重複參數裏面的方法就是序列類型scala.Seq [T]。

但是,此代碼:

abstract class A { def aSeq : Seq[A] } 
class B(val aSeq : A*) extends A 
class C extends B { override val aSeq :Seq[A] = Seq() } 

編譯時提供一個錯誤:

overriding value aSeq in class B of type A*; value aSeq has incompatible type 

編譯器似乎表明A *選自SEQ的獨特的類型[A] 。

調查的實際類ASEQ在這種情況下,表明它的一個實例scala.collection.mutable.WrappedArray $ ofRef但即使下面的代碼失敗,相同的消息編譯:

class C extends B { override val aSeq = new ofRef(Array[A]()) } 

所以問題是,我該如何重寫由班上重複參數定義的成員呢?

如果你想知道這是從哪裏來的,那就是scala.xml.Elem所做的,以覆蓋scala.xml.Node中的方法。

+0

我建議不使用的一類重複參數'val's(我有點驚訝它編譯所有) 。相反,如果你想讓語法B(a1,a2,...)有效,你可以在class B(val aSeq:Seq [A])中擴展A',並將它添加到伴隨對象中:'object B {def適用(aSeq:A *)=新B(aSeq)}'。 – 2011-04-01 13:29:33

+0

這不是我的代碼使用它。正如我在帖子末尾所說的,重複的參數被scala.xml.Node的scala.xml.Elem子類使用。我沒有選擇改變它。 – DougC 2011-04-01 13:40:06

+0

啊,我誤解了。剛剛檢查過'scala.xml.Node'而不是'scala.xml.Elem'。 – 2011-04-01 13:46:02

回答

5

您的問題可以概括爲:

scala> class A { def aSeq(i: Int*) = 1 } 
defined class A 

scala> class B extends A { override def aSeq(i: Seq[Int]) = 2 } 
<console>:6: error: method aSeq overrides nothing 
     class B extends A { override def aSeq(i: Seq[Int]) = 2 } 

的方法有不同的類型。該規範表示(重點煤礦):

這樣的重複參數的類型內該方法則序列類型scala.Seq [T]

Int*作爲和Seq[Int]不在該方法內部,這個特定的句子不適用。

有趣的是,下面的代碼顯示該方法具有擦除但同樣的前後不同的類型:

scala> class G { def aSeq(i:Int*) = 1; def aSeq(i:Seq[Int]) = 2 } 
<console>:5: error: double definition: 
method aSeq:(i: Seq[Int])Int and 
method aSeq:(i: Int*)Int at line 5 
have same type after erasure: (i: Seq)Int 
     class G { def aSeq(i:Int*) = 1; def aSeq(i:Seq[Int]) = 2 } 

所以,問題就變成了,爲什麼你的B類可以擴展你的A抽象類。那裏的規格可能會有不一致。我不知道...

編輯:我重新讀了規範,我無法弄清楚是否有任何與重複參數和覆蓋有關的東西。似乎沒有任何關於重複參數的返回類型,這是您獲取val aSeq訪問器方法的方法。

我認爲馬克的回答是完全有效的方法。如果你不能跟着它,你可以使用以下解決方法:

class C extends B { 
    private def aSeqHelper(a: A*) = a 
    override val aSeq = aSeqHelper(Seq[A](): _*) 
} 

因此,例如:

import scala.xml._ 
class ElemX extends Elem("pref", "label", <xml a="b"/>.attributes, TopScope) { 
    private def childHelper(c: Node*) = c 
    override val child = childHelper(<foo/><bar/>: _*) } 

然後:

scala> new ElemX 
res4: ElemX = <pref:label a="b"><foo></foo><bar></bar></pref:label> 
+0

我找不到任何語言規範,甚至指的是在類參數中使用重複的參數,更不用說param是val時生成的成員類型。 – DougC 2011-04-01 13:44:31

+0

爲什麼可以重寫的最簡單的解釋是,編譯器可能會認爲'A *'是'Seq [A]'的一個子類型(但不能在參數列表之外使用)。 – 2011-04-01 13:51:28

+0

它似乎好像編譯器將它視爲完全不同的類型。 – DougC 2011-04-01 13:54:12

4

xml.Elem複製方法使用它像這樣

def copy(
    prefix: String = this.prefix, 
    label: String = this.label, 
    attributes: MetaData = this.attributes, 
    scope: NamespaceBinding = this.scope, 
    child: Seq[Node] = this.child.toSeq 
): Elem = Elem(prefix, label, attributes, scope, child: _*) 

所以,你可以在B構造

class C extends B(aSeq = Seq(): _*) 

覆蓋值或聲明它作爲類C

class C(seq: Seq[A]) extends B(aSeq = seq: _*) 

的參數雖然我不知道它回答您的問題!

+0

這並不完全符合我的需要。我需要能夠在C中覆蓋B中的aSeq成員,而不是僅僅在構造時初始化它的值。 – DougC 2011-04-02 11:02:01