Звездная проекция в Котлине - PullRequest
4 голосов
/ 13 апреля 2019

Может кто-нибудь помочь мне объяснить, что здесь происходит?

private val map1 = mutableMapOf<String, Data<State<*>>>()
private val map2 = mutableMapOf<String, Data<*>>()

init {
    map1.put("1", Data<State<String>>()) //it does not work
    map2.put("2", Data<State<String>>()) //it works
    map2.put("3", Data<State<Int>>()) //it works
}

class Data<T>
class State<T>

Я прочитал в Kotlin docs, что если тип неизвестен, вы можете использовать Star Projection (*), а затем использовать любой тип. Так почему же это не работает для первого случая? Там написано Ошибка несоответствия типов.

Ответы [ 3 ]

2 голосов
/ 13 апреля 2019

Data<*> является распространенным супертипом Data<String>, Data<Any>, Data<AnythingYouPutThere>.Но Data<State<*>> не распространенный супертип Data<State<String>> и т. Д .;Data с определенным параметром типа State<*> (который является супертипом State<String> и т. д.)

К сожалению, Kotlin не поддерживает общие экзистенциальные типы, как это делает Scala, но в этих терминах Data<State<*>> это Data<State<T> forSome T> пока вы хотите Data<State<T>> forSome T.

Я установил mutableMapOf<String, Data<State<*>>>() на mutableMapOf<String, Data<out State<*>>>(), и это сработало.Я не знаю, почему

Data<out State<*>> допускает любой подтип State<*> в качестве параметра типа Data.Так что это также может быть выражено как экзистенциальный тип: Data<T> forSome T : State<*>, который не вполне Data<State<T>> forSome T, потому что State<*> может иметь подтипы, которые не State<Something>.Например, если у вас есть class State2 extends State<Int>(), Data<out State<*>> позволяет Data<State2>, но Data<State<T>> forSome T не будет.

1 голос
/ 13 апреля 2019

Ознакомьтесь с документами по Проекция и декларация дисперсии

В нем говорится, что out должен сообщить компилятору тип <>

0 голосов
/ 13 апреля 2019

Согласно документам, скажем, у вас есть класс

class Source<X>

, вы не можете сделать это

val source: Source<Any> = Source<String>()

, даже если String наследуется от Any.Это называется инвариантностью.Для поддержки этой функции вам придется использовать декларацию сайта Kotlin.Вам просто нужно добавить модификатор out к параметру типа X.

class Source<out X>

Подвох в том, что вы не можете использовать X ни в одном из методов класса Source, например:

class Source<out X> {
    fun modifyX(x: X) {} //not allowed
}

Вы можете создать только X, т. Е. Установить тип возвращаемого значения для методов X

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