Scala - доминирующий тип-член с границами - PullRequest
0 голосов
/ 20 декабря 2018

У меня есть следующая проблема с иерархией черт в 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 , 2 ), кажется, сосредоточены на других аспектах, чем у меня, и я действительно в растерянности, потому что я не могу найти много информации о таком поведениив Скале.

Шаблон кода Scala этого вопроса можно найти на scastie

1 Ответ

0 голосов
/ 20 декабря 2018

Это работает:

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[_]] приведет к отображению «голого» значения и «обернутого» значения с несовместимыми типами.

...