scala - 具有覆盖抽象类型的蛋糕模式不适用于类型上限

标签 scala dependency-injection traits cake-pattern

我想用 <: 覆盖特征中的抽象类型而不是 = (就像这里的回答 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

最佳答案

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

此外,特质的自我类型

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

被隐式扩充为
trait S { this: S with C => ... }

这样就可以在 S 中访问 trait S 中的定义。在你的情况下,trait 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 中,而不是根据线性化顺序选择单个成员,那将会更清晰。这是我们将来要考虑的更改,但我们需要注意向后兼容性。

关于scala - 具有覆盖抽象类型的蛋糕模式不适用于类型上限,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10213395/

相关文章:

scala - 如何将完全输出模式下的流聚合保存到 Parquet?

scala - SBT:如何同时包含相同依赖项的普通 jar 和 test-jar

dependency-injection - Dagger 2 - 缺少构造函数注入(inject)示例

c# - 使用 SimpleInjector 的同一组单例进行多个 RegisterAll 注册

methods - 有没有一种方法可以使用后缀表示法来调用 Rust 中的函数而不需要定义新的特征?

generics - Rust 实现功能只要 `Integer::from` 有效

java - Scala 包装通用匿名类

json - 在 Scala 中提取 json

java - Java ServiceLoader 在开发期间如何工作? (构建 JAR 之前的单元测试?)

string - 在 Rust 中,将 &str 拆分为每个包含一个字符的 &strs 迭代器的惯用方法是什么?