覆盖Scala中重复的类参数?

时间:2011-04-01 10:57:03

标签: scala

Scala语言规范2.8版的第4.6.2节描述了重复的参数,并说:

  

参数部分的最后一个值参数可以以“*”为后缀,例如(...,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中覆盖方法所做的事情。

3 个答案:

答案 0 :(得分: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访问器方法获得的内容。

我认为Mark的答案是一种非常有效的方法。如果您无法遵循它,您可以使用以下解决方法:

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>

答案 1 :(得分: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: _*)

虽然我不确定它会回答你的问题!

答案 2 :(得分:3)

规范从未允许重复类型以这种方式泄漏。 2011年7月更改了编译器以强制执行此操作。

有关更多背景信息,请查看故障单中的评论:

https://issues.scala-lang.org/browse/SI-4176