Scala - 覆盖带有边界的类型成员

you*_*tur 5 generics scala traits type-bounds type-members

我在Scala代码中的traits层次结构存在以下问题:

首先,我有一个MyTrait[A]具有这样定义的基本特征:

trait MyTrait[A] {
  def v1: A
}
Run Code Online (Sandbox Code Playgroud)

然后是一个Base带有类型成员的特征定义:

trait Base[A] {
  type T <: MyTrait[A]
  val baseV: T
}
Run Code Online (Sandbox Code Playgroud)

并且,最后,一个特征Gen覆盖了Base类型成员.

trait Gen[A, X <: MyTrait[A]] extends Base[A] {
  type T = X
}
Run Code Online (Sandbox Code Playgroud)

问题是在Gen特征中似乎丢失了类型成员的边界.这可以通过以下测试证明:

编译:

trait Test1 {
  val x: Base[_]
  println(x.baseV.v1)
}
Run Code Online (Sandbox Code Playgroud)

不编译(value v1 is not a member of Test2.this.x.T):

trait Test2 {
  val x: Gen[_, _]
  println(x.baseV.v1)
}
Run Code Online (Sandbox Code Playgroud)

我想知道这是语言的限制还是有解决方法.针对以上类似问题上stackowerflow问题(1,2)似乎把重点放在比我的不同方面,我真的不知所措,因为我无法找到有关Scala的这种行为多的信息.

可以在scastie上找到此问题的Scala代码模板

HTN*_*TNW 5

这有效:

trait Test2 {
  val x: Gen[A, X] forSome { type A; type X <: MyTrait[A] }
  println(x.baseV.v1)
}
Run Code Online (Sandbox Code Playgroud)

我相信问题是这样的

Gen[_, _]
Run Code Online (Sandbox Code Playgroud)

不得不说

Gen[_ >: Nothing <: Any, _ >: Nothing <: Any]
Run Code Online (Sandbox Code Playgroud)

哪个是一样的

Gen[A, X] forSome { type A; type X }
Run Code Online (Sandbox Code Playgroud)

也就是说,即使边界GenX <: MyTrait[A],通配符也没有继承那个边界.你可以在这里看到类似的问题:

trait Data { def data: String }
trait Box[A <: Data] { def data: A }
def unbox(b: Box[_]): String = b.data.data // nope; the wildcard is not <: Data
Run Code Online (Sandbox Code Playgroud)

我们可以明确地将通配符添加到通配符.但是,因为第二个通配符上的绑定取决于第一个通配符forSome,所以我们不得不使用扩展语法来存在,所以我们可以命名A并使用它两次.

Gen[A, _ <: MyTrait[A]] forSome { type A }
Run Code Online (Sandbox Code Playgroud)

我选择将所有内容都放在存在主义条款中,这相当于:

Gen[A, X] forSome { type A; type X <: MyTrait[A] }
Run Code Online (Sandbox Code Playgroud)

你也可以使用

Gen[_, _ <: MyTrait[_]]
Run Code Online (Sandbox Code Playgroud)

但这不等同,因为它与左右参数无关.如果除了a之外还Gen[A, _]包含A一个MyTrait[A],那么using x: Gen[_, _ <: MyTrait[_]]会使用不兼容的类型呈现"裸"值和"包装"值.