Scala - 用边界覆盖类型成员

Scala - overriding type-member with bounds

我对 Scala 代码中的特征层次结构有以下问题:

首先,我有一个基本特征MyTrait[A],定义如下:

trait MyTrait[A] {
  def v1: A
}

然后是具有类型成员的特征Base的定义:

trait Base[A] {
  type T <: MyTrait[A]
  val baseV: T
}

最后,一个特征 Gen 覆盖了 Base 的类型成员。

trait Gen[A, X <: MyTrait[A]] extends Base[A] {
  type T = X
}

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

编译:

trait Test1 {
  val x: Base[_]
  println(x.baseV.v1)
}

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

trait Test2 {
  val x: Gen[_, _]
  println(x.baseV.v1)
}

我想知道这是语言的限制还是有解决方法。关于 stackowerflow (1, ) 上类似主题的问题似乎侧重于与我不同的方面,我真的很茫然,因为我在 Scala 中找不到有关此类行为的太多信息。

本题的Scala代码模板可以在scastie

找到

这个有效:

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

我认为问题在于

Gen[_, _]

Has to mean

Gen[_ >: Nothing <: Any, _ >: Nothing <: Any]

相同
Gen[A, X] forSome { type A; type X }

也就是说,即使 Gen 上的界限表示 X <: 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

我们可以明确地为通配符添加界限。然而,因为第二个通配符的绑定依赖于第一个通配符,我们被迫使用扩展的 forSome 语法来表示存在,所以我们可以命名 A 并使用它两次。

Gen[A, _ <: MyTrait[A]] forSome { type A }

我选择将所有内容都放在存在子句中,这等价于:

Gen[A, X] forSome { type A; type X <: MyTrait[A] }

您也可以使用

Gen[_, _ <: MyTrait[_]]

但这并不等价,因为它没有关联左右参数。如果 Gen[A, _] 除了 MyTrait[A] 之外还包含 A,那么使用 x: Gen[_, _ <: MyTrait[_]] 将呈现 "bare" 值和 "wrapped" 值不兼容的类型.