Что означает оператор * (звёздочка) перед переменной в Kotlin? Spread Operator
Что такое Spread Operator (*) в Kotlin?
Оператор * (звёздочка) перед переменной в Kotlin называется Spread Operator (оператор распространения). Он используется для "разворачивания" содержимого массива в список аргументов, особенно когда функция ожидает vararg (variable number of arguments). Это прямой аналог spread operator из Java, но в Kotlin он применяется только к массивам, а не к коллекциям.
Зачем он нужен?
В Kotlin многие функции принимают vararg — переменное количество аргументов одного типа. Например, listOf(), arrayOf(), setOf() и пользовательские функции. Если у вас уже есть массив (тип Array) и вы хотите передать его элементы как отдельные аргументы, без spread operator вы передадите сам массив как единый объект.
Пример с listOf()
Рассмотрим ваш пример подробнее:
val numbers = listOf(1, 2, 3)
val moreNumbers = listOf(0, *numbers.toTypedArray(), 4, 5)
println(moreNumbers) // [0, 1, 2, 3, 4, 5]
numbers.toTypedArray()— преобразует списокList<Int>в массивArray<Int>.*numbers.toTypedArray()— разворачивает массив, передавая каждый его элемент как отдельный аргумент вlistOf().- Без
*вы бы передали сам объект массива, и он попал бы в список целиком (как один элемент).
Spread Operator с vararg-функциями
Самый частый сценарий использования — передача массива в функцию, объявленную с vararg:
fun printAll(vararg strings: String) {
for (s in strings) {
println(s)
}
}
fun main() {
val array = arrayOf("A", "B", "C")
// Без spread — передаём массив как один аргумент
// printAll(array) // Ошибка компиляции: требуется String, получен Array<String>
// Со spread — передаём элементы массива
printAll(*array) // Работает: выведет A, B, C
// Можно комбинировать с другими аргументами
printAll("Start", *array, "End") // Выведет: Start, A, B, C, End
}
Важные ограничения
- Работает только с массивами (
Array<T>), не с коллекциями (List,Setи т.д.). Для коллекций нужно сначала преобразовать их в массив через.toTypedArray(). - Только для vararg — spread operator нельзя использовать в других контекстах (например, при присваивании или в обычных вызовах функций).
- Тип массива должен совпадать с типом vararg. Для примитивных типов используйте соответствующие массивы:
IntArray,DoubleArrayи т.д.
Альтернативы и лучшие практики
Если вы работаете преимущественно с коллекциями, старайтесь избегать spread operator, так как преобразование списка в массив — лишняя операция. Вместо этого используйте:
val numbers = listOf(1, 2, 3)
val moreNumbers = listOf(0) + numbers + listOf(4, 5)
// или
val moreNumbers2 = buildList {
add(0)
addAll(numbers)
add(4)
add(5)
}
Эти подходы более идиоматичны для Kotlin и не требуют преобразования в массив.
Производительность
Spread operator создаёт копию массива при передаче в vararg. Для больших массивов это может быть накладно. В таких случаях рассмотрите использование buildList или mutableListOf с addAll.
Итог
Spread operator (*) — это мост между миром массивов и vararg-функций. Используйте его, когда нужно передать элементы массива как отдельные аргументы, но старайтесь минимизировать его применение в пользу более идиоматичных для Kotlin конструкций с коллекциями.
Spread Operator для примитивных массивов
В Kotlin есть специальные типы массивов для примитивов: IntArray, DoubleArray, BooleanArray и т.д. Spread operator работает и с ними, но есть нюансы.
Пример с IntArray
fun sum(vararg numbers: Int): Int = numbers.sum()
fun main() {
val intArray = intArrayOf(10, 20, 30)
// Работает напрямую, без toTypedArray()
val result = sum(*intArray)
println(result) // 60
// Комбинируем с обычными числами
val result2 = sum(1, *intArray, 2)
println(result2) // 63
}
Почему это удобно?
Примитивные массивы (IntArray) не нужно преобразовывать в Array<Int> — spread operator работает с ними напрямую. Это экономит память и время, так как не происходит упаковка (boxing) примитивов в объекты.
Когда стоит использовать spread operator?
- Когда вы получаете массив из Java-кода или из внешней библиотеки.
- Когда работаете с функциями, которые принимают
varargи вы не можете изменить их сигнатуру. - В однострочных решениях для быстрой конкатенации (например,
listOf(*array)).
Чего следует избегать?
Не используйте spread operator для преобразования списка в массив только ради того, чтобы потом развернуть его. Вместо этого используйте addAll() или оператор + для коллекций. Это делает код более читаемым и эффективным.
Пример плохого кода:
// Плохо: лишнее преобразование
val list = listOf(1, 2, 3)
val bad = listOf(0, *list.toTypedArray(), 4)
// Хорошо: работаем с коллекциями напрямую
val good = listOf(0) + list + listOf(4)
Помните: spread operator — это инструмент для совместимости, а не основной способ работы с данными в Kotlin. Используйте его осознанно.
Ответов пока нет.
Войдите чтобы оставить ответ
Блоги