Это работает:
trait Test2 {
val x: Gen[A, X] forSome { type A; type X <: MyTrait[A] }
println(x.baseV.v1)
}
Я считаю, что проблема в том, что
Gen[_, _]
должно означать
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, _]
содержит A
в дополнение к MyTrait[A]
, то использование x: Gen[_, _ <: MyTrait[_]]
приведет к отображению «голого» значения и «обернутого» значения с несовместимыми типами.