在 Scala 中重写重复的类参数?

发布于 2024-10-28 11:51:10 字数 815 浏览 3 评论 0原文

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 中的 child 方法的方法。

Section 4.6.2 of the Scala Language Specification Version 2.8 describes repeated parameters and says:

The last value parameter of a parameter section may be suffixed by “*”, e.g. (..., x:T*). The type of such a repeated parameter inside the method is then the sequence type scala.Seq[T].

However, this code:

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

give an error when compiled:

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

The compiler seems to indicate that A* is a distinct type from Seq[A].

Investigating the actual class of aSeq in this case shows it to be an instance of scala.collection.mutable.WrappedArray$ofRef but even the following code fails to compile with the same message:

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

So the question is, how do I go about overriding a member defined by a repeated parameter on the class?

In case you're wondering where this is coming from, that is exacly what scala.xml.Elem does to override the child method in scala.xml.Node.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

掌心的温暖 2024-11-04 11:51:10

您的问题可以概括为:

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]

As 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>

Your issue can be summarized as:

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 }

The methods have different types. The spec says (emphasis mine):

The type of such a repeated parameter inside the method is then the sequence type scala.Seq[T]

As Int* and Seq[Int] aren't inside the method, this particular sentence does not apply.

Interestingly, this following code shows that the methods have different types before erasure but the same after:

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 }

So the question then becomes, why your B class can extend your A abstract class. There may be an inconsistency in the spec there. I don't know...

Edit: I re-read the spec and I can't figure out if there is anything related to repeated parameters and overriding. There does not seem to be anything about return type of repeated parameters, which is what you get for the val aSeq accessor method.

I think Mark's answer is a perfectly valid approach. In case you can't follow it, you can use the following workaround:

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

So for instance:

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/>: _*) }

Then:

scala> new ElemX
res4: ElemX = <pref:label a="b"><foo></foo><bar></bar></pref:label>
往日情怀 2024-11-04 11:51:10

xml.Elem的copy方法是这样使用的

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的参数code>

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

虽然我不确定它是否回答了你的问题!

The copy method of xml.Elem uses it like this

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: _*)

So you can override the value in the B constructor

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

Or declare it as a parameter of the class C

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

Though I am not sure it answers your question!

擦肩而过的背影 2024-11-04 11:51:10

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

有关更多背景信息,请查看票证中的评论:

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

The spec never allowed for repeated types to leak out in this way. The compiler was changed in July 2011 to enforce this.

For more background, check out the comments in the ticket:

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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文