8

我想用<:而不用覆盖特征中的抽象类型=(就像这里的回答Scala Upper Bounds : value is not a member of type parameter)。

我想使用蛋糕图案,但这不起作用,我不明白为什么?

trait A {
  def ping = println("ping")
}

trait Cake {
  type T
}

trait S { this: Cake =>
  type T = A
  def t: T
  t.ping
}

好的,这个例子运行了,但是在我的实际用例中,我想用<:而不是用覆盖类型。=似乎无法访问 t 函数,为什么?

trait S { this: Cake =>
  type T <: A
  def t: T
  t.ping
}

返回错误value ping is not a member of S.this.T

4

1 回答 1

15

这是 Scala 类型系统的一个缺点。在确定 mixin 中的成员时,Scala 使用两条规则:首先,具体总是覆盖抽象。其次,如果两个成员都是具体的,或者都是抽象的,那么在线性化顺序中后面的那个会获胜。

此外,特质的自我类型

trait S { this: C => ... }

被隐式扩充为

trait S { this: S with C => ... }

以便可以在 S 中访问特征 S 中的定义。在您的情况下,特征 S 被视为:

trait S { this: S with Cake =>
  type T = A
  def t: T
  t.ping
}

现在,只要 T 是具体的就可以了,因为它覆盖了 Cake 中的抽象 T。但是如果 T 是抽象的,那么 Cake 中的那个在线性化顺序中排在后面并获胜。并且那个 T 没有上限,所以没有成员 ping。解决此问题的一种方法是通过编写以下内容来更改线性化顺序:

trait S { this: Cake with S =>
  type T <: A
  def t: T
  t.ping
}

如果 Scala 有一条不同的规则,即所有抽象类型成员的约束都合并到 mixin 中,而不是根据线性化顺序选择单个成员,那会更简洁。这是我们将来要考虑的更改,但我们需要注意向后兼容性。

于 2012-04-19T07:21:03.230 回答