Scala内部类型作为抽象方法参数

时间:2011-08-15 21:00:39

标签: scala

在一些需要对内部特征/类进行子类化的代码中,我在成功实现抽象方法时遇到了麻烦,显然是因为我的类型签名不匹配。例如:

trait Outer {
  trait Inner
  def score(i:Inner): Double
}
class Outer2 extends Outer {
  class Inner extends super.Inner
  def score(i:Inner) = 0.0
}

您可能认为Outer2.score无法成功实施Outer.score,因为Outer2.this.Inner类型与Outer.this.Inner不匹配。但是来自scala-2.9.0.1的编译错误消息并未指出这一点。它说:

error: class Outer2 needs to be abstract, since method score in trait Outer 
of type (i: Outer2.this.Inner)Double is not defined
(Note that Outer.this.Inner does not match Outer2.this.Inner)

它说它期待Outer2.this.Inner类型的参数!这实际上就是我想要的行为。但为什么我的第二个score定义不能成功匹配抽象方法的类型?

我尝试使用以下替代代码使编译器更清楚,但我也得到了同样令人困惑的错误消息。

trait Outer[This<:Outer[This]] {
  this: This =>
  trait Inner
  def score(i:This#Inner): Double
}
class Outer2 extends Outer[Outer2] {
  class Inner extends super.Inner
  def score(i:Outer2#Inner) = 0.0
}

2 个答案:

答案 0 :(得分:4)

您无法在重写方法中细化方法参数的类型。

这有效:

class Outer2 extends Outer {
  def score(i: super[Outer].Inner) = 0.0 

  // Or just:
  // def score(i: super.Inner) = 0
}

考虑编译器是否允许您的代码:

trait Outer {
  trait Inner
  def score(i:Inner): Double
}
class Outer2 extends Outer {
  class Inner extends super.Inner { def foo = "!" }
  def score(i:Inner) = { i.foo; 0.0 }

  // !!! unsafe, no `foo` method
  score(new super[Outer].Inner{})
}

重写方法可能具有更具体的返回类型,因为这不会导致代码不健全。 (在JVM级别,返回类型包含在方法签名中,创建Bridge方法以允许调用者针对超类中的签名进行编程并分派到子类中的实现。)

答案 1 :(得分:2)

这可能是一种合适的解决方法,具体取决于具体要求:

trait Outer {
  trait InnerI
  type Inner <: InnerI
  def score(i:Inner): Double
}

class Outer2 extends Outer {
  class InnerI extends super.InnerI
  type Inner = InnerI
  def score(i:Inner) = 0.0
}