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

У меня есть функция, которая принимает в Array<String?> :

 fun doStuff(words: Array<String?>) { // ... } 

Есть ли способ, которым я могу передать в Array<String> эту функцию? As-компилятор дает мне ошибку «несоответствие типа».

 private val SOME_WORDS = arrayOf("I", "want", "to", "use", "these") doStuff(SOME_WORDS) // throws a type-mismatch error 

Предпочтительно, я хотел бы избежать сделать SOME_WORDS arrayOf<String?>(...) если это возможно.

Используйте out -projected Array<out String?> :

 fun doStuff(words: Array<out String?>) { /* ... */ } 

Массивы в Котлине являются инвариантными , что означает, что Array<A> и Array<B> не являются подтипами друг друга для любых разных A и B , включая String и String? , и они не могут быть назначены и переданы как аргументы друг на друга.

Использование out -projection Array<out String?> Заставляет функцию принимать не только Array<String?> Но также массивы с подтипами String? , В принципе, поскольку тип является final , существует только один такой подтип, и это String (ненулевой, без ? ).

диаграмма дисперсии типа

Фотография взята из: Вихревой тур по иерархии типа Котлин )

Таким образом, функция будет принимать Arrray<String> . Но вы не сможете поместить значения NULL в массив (так работает проекция), поэтому безопасность типа (и нуль-безопасность) сохраняется.

Проблема здесь в разнообразии . String – это подтип ее нулевой друга String? но в Kotlin это не означает, что Array<String> является подтипом Array<String?> потому что массивы инвариантны . (В Java это не так, по умолчанию ковариантные массивы)

Если у вас есть такая функция, как ваша, которая ожидает аргумент типа Array<String?> Вы можете передать Array<String?> , Поэтому Array<String> невозможен! Если вы хотите включить свой метод для обработки этих массивов, выполните следующие действия:

 fun doStuff(words: Array<out String?>) { // ... } 

Это позволяет передавать words массива ковариантными и подтипы Array<String?> .

Имейте в виду, что для таких «проецируемых» массивов доступны только такие функции, как get() . Говорят, что words параметра являются производителем String? ,

Если вы хотите узнать больше об этом, посмотрите официальные документы 🙂

Вы должны использовать проекцию типа out, поскольку общий тип Array<String> расширяет Any а не Array<String?> В Kotlin, например:

 // v--- use out type projection here fun doStuff(words: Array<out String?>) { // ... } 

Общий наследование

Когда использование проекции типа в Котлине похоже на верхний ограниченный шаблон ? extends T ? extends T в Java. и String является подмножеством String? в Kotlin, поэтому Array<String> расширяет Array<String?> в Котлине. Поскольку вы можете видеть, что левая часть диаграммы наследования – это верхняя ограниченная наследование.

Верхний ограниченный шаблон