Давайте сделаем пару наблюдений и поэкспериментируем с несколькими способами, позволяющими компилятору определиться с вашим типом возвращаемого значения:
1) Обратите внимание, что оператор if (value) List[T]() else List[Option[String]]()
возвращает 2 различных конкретных типа, но оператор if
должен возвращать тот же тип из своих предложений then и else. Поэтому, когда этот оператор возвращает значение, компилятору нужно будет вывести наиболее общий тип для двух предложений, чтобы ввести согласованное ограничение.
2) Обратите внимание, что переменная типа T
зависит от точного типа, который вы передаете при вызове a()
, например a[scala.io.Source]()
. В объявлении метода вы задали T
верхнюю границу T <: AnyRef
, что означает, что компилятор должен найти наиболее общий тип, представляющий собой объединение любого типа, являющегося подтипом AnyRef и Option [String].
3) Обратите внимание на тип возвращаемого значения, выведенный компилятором, удалив объявление типа возвращаемого значения. то есть def a[T <: AnyRef]() = if (true) List[T]() else List[Option[T]]()
.
Компилятор дал a()
тип возврата List[AnyRef]
. Этот вид имеет смысл, потому что это единственная возможность для самого общего типа между чем-либо T
, который является подтипом AnyRef
и Option[of that anything T]
.
4) Теперь попробуйте def a[T <: AnyRef]() = if (true) List[T]() else List[Option[String]]()
. Предполагаемый тип возвращаемого значения теперь List[java.lang.Object]
. Причина в том, что класс String
в Scala 2.8 на самом деле java.lang.String
, поэтому, по моим лучшим предположениям, теперь самый общий тип должен избегать иерархии scala.*
и в конечном итоге оказаться в java.lang.Object
по неизвестным причинам.
5) Поскольку AnyRef
на самом деле является просто псевдонимом java.lang.Object
, вы можете сделать def a[T <: AnyRef](): List[AnyRef] = if (true) List[T]() else List[Option[String]]()
для принудительного возврата типа List[AnyRef]
.
Если вы просто хотите вернуть какой-либо подтип AnyRef, вам в основном нужно сделать следующее:
def a(): List[AnyRef] = ...
, который в основном возвращает суперкласс, и вы должны бросить возвращенный List[AnyRef]
, используя .asInstanceOf[T]
. В качестве альтернативы:
def a[T <: AnyRef](): List[T] = List[T]()
даст вам определенный тип T, но вы не можете вернуть 2 разных типа в операторе if
, как в вашем примере, где один может быть более конкретным, а другой - и ожидать, что он всегда будет возвращать более конкретный Тип, предоставленный вами при вызове метода. Поскольку компилятор не может гарантировать, что тип в вашем операторе if
всегда будет List [T], просто выполняя проверку типов. Я сделал это яснее?