Вариативность на месте использования
Проекции типов
«Вариативность на месте использования» — бесплатный урок Kotlin Academy на CoddyKit. Это урок 3 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения Kotlin Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс Kotlin Academy содержит 4 уроков всего.
Вариантность в месте использования
Иногда обобщённый класс в целом инвариантен, но конкретная функция только производит или только принимает тип. Вариантность в месте использования, то есть проекции типов, применяет out или in непосредственно там, где используется тип.
Зачем нужна вариантность в месте использования
Инвариантный класс, такой как MutableList<T>, нельзя сделать ковариантным при объявлении, поскольку он и читает T, и записывает T. Но конкретная функция может только читать из него, и проекции позволяют безопасно выразить это.
Проекция out
Запись Array<out T> в качестве типа параметра создаёт ковариантное представление: из него можно читать T, но нельзя записывать T. Благодаря этому можно передать Array<String> туда, где ожидается Array<out Any>.
fun printArray(items: Array<out Any>) {
for (item in items) println(item)
}
fun main() {
val names: Array<String> = arrayOf("Ann", "Bob")
printArray(names)
}Только чтение
При проекции out компилятор разрешает чтение, то есть вывод, но запрещает запись, то есть ввод, поскольку запись могла бы нарушить типобезопасность исходного массива.
Проекция in
Запись Array<in T> создаёт контравариантное представление: в него можно записывать T, но при чтении элементы возвращаются как Any?. Это позволяет принимать массивы типа T или любого надтипа.
fun fill(dest: Array<in Int>, value: Int) {
for (i in dest.indices) dest[i] = value
}
fun main() {
val numbers: Array<Number> = arrayOf(0, 0, 0)
fill(numbers, 7)
println(numbers.toList())
}Только запись
При проекции in можно записывать значения типа T, то есть выполнять ввод, но при чтении тип элемента рассматривается как самый общий тип, поскольку фактический тип элемента может быть любым надтипом.
Проекции и объявление вариантности
Вариантность, объявленная в месте определения, например class Box<out T>, применяется везде, где используется класс. Проекции в месте использования, например Box<out T> в качестве параметра, действуют только в этом конкретном месте. Используйте проекции, когда сам класс должен оставаться инвариантным.
Звёздная проекция
Если аргумент типа вообще не имеет значения, используйте звёздную проекцию *. List<*> означает список некоторого неизвестного типа: элементы можно читать как верхнюю границу, но безопасно записывать их нельзя.
fun printSize(collection: List<*>) {
println("Size: ${collection.size}")
}
fun main() {
printSize(listOf(1, 2, 3))
printSize(listOf("a", "b"))
}Ограничения звёздной проекции
С помощью * по-прежнему можно вызывать члены, не зависящие от типа (например, size), и читать элементы как Any?, но нельзя добавлять элементы, поскольку настоящий тип неизвестен.
fun main() {
val unknown: List<*> = listOf("x", "y")
val first: Any? = unknown.first()
println(first)
}Выбор проекции
Используйте out T, когда функция только читает данные, in T, когда она только записывает данные, и *, когда точный тип не имеет значения. Эти проекции позволяют гибко и безопасно использовать инвариантные классы.
Связь с подстановочными типами Java
Проекции Kotlin out T и in T соответствуют подстановочным типам Java ? extends T и ? super T. Если Вы знакомы с обобщёнными типами Java, проекции покажутся Вам знакомыми.
Быстрая проверка
Что можно делать с параметром типа Array<out Any>?
Повторение
Вариантность на месте использования задаётся с помощью проекций out (только для чтения) или in (только для записи) в конкретном месте использования, а * используется как звёздная проекция, когда тип неизвестен. Это делает инвариантные классы гибкими, не требуя изменять их объявление. Далее Вы ограничите параметры типов с помощью ограничений обобщённых типов.
Часто задаваемые вопросы
Урок «Вариативность на месте использования» бесплатный?
Да — полный текст урока «Вариативность на месте использования» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс Kotlin Academy, подпишись на CoddyKit PRO. Курс Kotlin Academy содержит 4 уроков всего.
Чему я научусь в уроке «Вариативность на месте использования»?
Проекции типов Ты практикуешь Kotlin Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.
Нужен ли мне опыт, чтобы начать Kotlin Academy?
Предыдущий опыт не требуется. Kotlin Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 3 из 4.
Сколько времени занимает урок «Вариативность на месте использования»?
Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.
Можно ли писать и запускать код в этом уроке Kotlin Academy?
Да. Каждый урок Kotlin Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.
Все уроки этого курса
- Обобщённые функции и классы
- Вариативность на месте объявления
- Вариативность на месте использования
- Ограничения обобщений