Метод возвращаемый тип ковариация - PullRequest
2 голосов
/ 09 февраля 2011

Как я могу определить, что метод возвращает List [+ AnyRef]?Я попытался:

def a[T <: AnyRef](): List[T] = List[AnyRef]() 

Но по какой-то причине он не компилируется.

РЕДАКТИРОВАТЬ : согласно Вонгу я должен использовать

def a[T <: AnyRef](): List[T] = List[T]()

но есть ли способ вернуть любой подтип AnyRef, например

def a[T <: AnyRef](): List[T] = if (value) List[T]() else List[Option[String]]()

Здесь Option [String] является потомком Anyref, но компилятор не принимает его

Так что mainвопрос в том, могу ли я объявить метод с ковариантным типом возврата, например List [+ AnyRef]

Ответы [ 3 ]

5 голосов
/ 09 февраля 2011

Давайте сделаем пару наблюдений и поэкспериментируем с несколькими способами, позволяющими компилятору определиться с вашим типом возвращаемого значения:

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], просто выполняя проверку типов. Я сделал это яснее?

3 голосов
/ 09 февраля 2011

Ваше определение

def a[T <: AnyRef](): List[T] = List[AnyRef]() 

не компилируется, поскольку возвращаемое значение равно List[AnyRef], а не List[T].И наоборот:

def a[T <: AnyRef](): List[AnyRef] = List[T]()

и буквально соответствует вашему вопросу, но ответ Вонга, вероятно, будет более полезным.

2 голосов
/ 09 февраля 2011

Подумайте о коде, вызывающем ваш метод. Например,

val x = a()

Какой тип x? Одна вещь, которую не может сказать, - это то, что тип x зависит от чего-то - он может только , зависит от статического контекста строки выше и сигнатуры типа метода. Так что пример, в котором вы возвращаете T или Option[String], может никогда не сработать, потому что нет способа определить, что будет возвращено из сигнатуры метода.

Каков именно ваш вариант использования? Как вы собираетесь использовать это, что вы хотите такую ​​вещь?

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