ПрограммированиеKotlin разработчик

Как работает 'vararg' в Kotlin? Опишите правила передачи, ограничения, взаимодействие с распространёнными паттернами и типичные сложности при комбинировании с именованными и обычными аргументами.

Проходите собеседования с ИИ помощником Hintsage

Ответ.

Ключевое слово vararg в Kotlin позволяет функции принимать переменное количество аргументов. Это эквивалентно массивам в Java, но с дополнительным синтаксическим сахаром.

Правила и ограничения:

  • Обычный синтаксис: fun foo(vararg numbers: Int)
  • Аргумент с vararg должен быть последним среди параметров функции (если после него есть параметры, то они должны быть именованными при вызове).
  • Передавать можно как отдельные значения, так и массив (с использованием оператора spread *).
  • Функцию с vararg можно вызвать без передачи значений этого аргумента.

Пример кода

fun printAll(vararg strings: String) { for (s in strings) println(s) } val arr = arrayOf("a", "b", "c") printAll("one", "two") // работать будет printAll(*arr) // spread (раскрывает массив)

Вопрос с подвохом.

Можно ли объявить два 'vararg'-параметра в одной функции или разместить 'vararg' не последним?

Ответ: Нет, в Kotlin можно использовать только один vararg в объявлении функции, он всегда должен быть последним по позиционным аргументам. Если после него добавить обычный параметр, он может быть передан только по имени.

Пример:

fun foo(vararg items: String, prefix: String) // Ошибка компиляции! // Верно: fun foo(vararg items: String, vararg items2: Int) // Ошибка компиляции! // Работает: fun foo(vararg items: String, prefix: String = "[default]") foo("a", "b", prefix = "->")

Примеры реальных ошибок из-за незнания тонкостей темы.


История

Молодой программист ошибочно полагал, что можно объявить два vararg-параметра сразу. Архитектура функции построилась так, что разделение стояло на нескольких уровнях вызова. Это привело к цепочке рефакторингов — пришлось пересматривать логику принимаемых данных и переписывать все вызовы.


История

На Android-проекте забыли использовать spread-оператор * при передаче массива в функцию с параметром vararg: printAll(arr) вместо printAll(*arr). В результате, вместо печати элементов массив был выведен как одна строка с адресом объекта, логически приложение вело себя странно.


История

В функции с vararg и дополнительными именованными параметрами fun foo(vararg a: Int, b: Int) вызовы через позиционные аргументы были восприняты некорректно: компилятор не мог определить где кончается список для vararg, а где начинается аргумент b, приводя к ошибкам времени компиляции. Решили явно использовать имена аргументов для таких параметров.