Тип извлечения из вида - PullRequest
0 голосов
/ 30 апреля 2020

Я хотел бы извлечь тип вида и использовать его для определения типа возвращаемого значения функции.

например.

Давайте определим черту Container.

trait Container[T] {
  def contained: T
}

Давайте определим черту Extra, чтобы мы могли расширить ее из нашего контейнера.

trait Extra[T] {
  def extra: T
}

Давайте определим черту ContainerExtractor как

trait ContainerExtractor[T, C <: Container[T]] {
  def extract(container: C): T
}

Теперь пользователи могут реализовать ContainerExtractor, выполнив

new ContainerExtractor[String, Container[String] with Extra[Int]] {
  override def extract(container: Container[String] with Extra[Int]): String = ???
}

Неплохо, хотя пользователь должен объявить тип внутри Container дважды! [String, Container[String] ... ]

Чтобы решить эту проблему с повторениями, я попытался обойти ее, переопределив Container и ContainerExtractor как

trait Container[T] {
  def contained: T
  final type Contained = T
}

trait ContainerExtractor[C <: Container[_]] {
  def extract(container: C): C#Contained
}

Таким образом (я надеялся) пользователи, которые хотят реализовать ContainerExtractor мог бы написать:

new ContainerExtractor[Container[String] with Extra[Int]] {
  override def extract(container: Container[String] with Extra[Int]): String =???
}

Хотя это не удается с:

incompatible type in overriding
def extract(container: Test.Container[String] with Test.Extra[Int]): _$2 (defined in trait ContainerExtractor);
found   : (container: Test.Container[String] with Test.Extra[Int])String
required: (container: Test.Container[String] with Test.Extra[Int])_$2

Поскольку компилятор не может сделать вывод, что тип, на который указывает подстановочный знак в C <: Container[_], является String в этой реализации черты.

Любая помощь в том, как избежать того, чтобы пользователь определял тип контейнера дважды при реализации ContainerExtractor?

1 Ответ

5 голосов
/ 30 апреля 2020

Проекция типа с помощью Class#T дает тип общего элемента c из класса вместо экземпляра класса. В вашем случае, если вы просто делаете C#Contained, это просто относится к типу члена C. Компилятор не знает, что такое C. Вместо этого вы должны получить тип члена из переменной:

trait ContainerExtractor[C <: Container[_]] {
  def extract(container: C): container.Contained
}
...