Почему Scala не полностью выводит параметры типа, когда параметры типа вложены? - PullRequest
13 голосов
/ 01 августа 2011

Рассмотрим следующий код Scala:

abstract class A
abstract class B[T <: A]
class ConcreteA extends A
class ConcreteB extends B[ConcreteA]

class Example[U <: B[T], T <: A]( resolver: U )
object Test {
    new Example( new ConcreteB )
}

Последняя строка new Example( new ConcreteB ) не компилируется со следующей ошибкой:

ошибка: выведенные аргументы типа [ConcreteB, Nothing] не соответствуют классу. Границы параметра типа примера [U <: B [T], T <: A] </p>

Но ConcreteB имеет все необходимые данные для разрешения как U , так и T. Что мне здесь не хватает?

Ответы [ 3 ]

10 голосов
/ 01 августа 2011

Киптон подошел ближе к своему решению с более высокой добротой. К сожалению, он споткнулся о том, что кажется ошибкой в ​​Scala <2.9.1.RC1. Следующее работает как и ожидалось с 2.9.1.RC1 и транком, </p>

Welcome to Scala version 2.9.1.RC1 (Java HotSpot(TM) Server VM, Java 1.7.0).
Type in expressions to have them evaluated.
Type :help for more information.

scala> abstract class A
defined class A

scala> abstract class B[T <: A]
defined class B

scala> class ConcreteA extends A
defined class ConcreteA

scala> class ConcreteB[T <: A] extends B[T]
defined class ConcreteB

scala> class Example[T <: A, U[X <: A] <: B[X]](resolver: U[T])
defined class Example

scala> new Example(new ConcreteB[ConcreteA])
res0: Example[ConcreteA,ConcreteB] = Example@ec48e7
10 голосов
/ 01 августа 2011

(См. Также два связанных вопроса: Scala не может вывести правильные аргументы типа и Тип, выведенный в Nothing в Scala )

Это выглядит как ограничениеВывод типа Scala, который намеренно не указан.В качестве обходного пути вы можете сделать вывод, сделав T тип член из B вместо параметра,

abstract class A
abstract class B { type T <: A }
class ConcreteA extends A
class ConcreteB extends B { type T = ConcreteA }
class Example[U <: B]( resolver: U )
object Test {
    new Example( new ConcreteB )
}

При использовании членов типа полезно знать, чтоих можно представить как параметры типа, используя уточнение, как в ответе Майлза Сабина на: Почему эта циклическая ссылка с проекцией типа недопустима?

В ответе Жан-Филиппа Пелле на связанный с этим вопрос , вывод типа помог, сделав параметр типа более привязанным.Если вы введете дополнительный параметр типа в ConcreteB, то вывод типа может сработать,

abstract class A
abstract class B[T <: A]
class ConcreteA extends A
class ConcreteB[T <: A] extends B[T]
class Example[T <: A, U[T0 <: A] <: B[T0]]( resolver: U[T] )
object Test {
  new Example( new ConcreteB[ConcreteA] )
}

Scala 2.9 выдает таинственное сообщение об ошибке ниже, но Майлз Сабин указывает, что этоошибка, которая будет исправлена ​​для 2.9.1

<console>:15: error: kinds of the type arguments (ConcreteA,ConcreteB[T0]) do not conform to the expected kinds of the type parameters (type T,type U) in class Example.
ConcreteB[T0]'s type parameters do not match type U's expected parameters: class ConcreteB has one type parameter, but type U has one
         new Example( new ConcreteB[ConcreteA] )
             ^
2 голосов
/ 20 февраля 2014

Я составил документ об обходных решениях типа на GitHub для моего собственного обучения.

Вот несколько простых правил, которые я считаю полезными:

  • Невозможно вывести параметры типа для параметров типа: Вывод типа Scala видит только типы, указанные в списке параметров (не путать с список параметров типа ).

  • Предыдущие параметры не используются для определения будущих параметров: Информация о типе передается только через параметр списки ,не параметры .


Однако в этом конкретном примере члены типа - это путь вперед (спасибо @Kipton Barros!)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...