Найти в Дзене
Nuances of programming

Ключевое слово vararg и оператор spread в Kotlin

Источник: Nuances of Programming Что осталось за кадром? В некоторых случаях необходимо определить функцию с переменным числом параметров; Вот пара примеров, с которыми вы, вероятно, сталкивались в Android:printf(String format, Obj... args)или execute(Params... params) из AsyncTask. Для начала разберем основы vararg и оператора spread, а затем подробно рассмотрим несколько сценариев, анализируя, что происходит за кадром. vararg в Kotlin Kotlin поддерживает объявление функции с переменным числом аргументов. Достаточно поставить перед названием параметра модификатор vararg: fun format(format: String, vararg args: Any). Несколько правил касательно vararg В Java параметр vararg должен быть последним в списке параметров — поэтому параметр vararg может быть только один. В Kotlin vararg не обязательно должен занимать последнее место в списке, однако использование нескольких параметров vararg все же недопустимо. Рассмотрим декомпилированный исходный код Java при объявлении параметров vararg.
Оглавление

Источник: Nuances of Programming

Что осталось за кадром?

В некоторых случаях необходимо определить функцию с переменным числом параметров; Вот пара примеров, с которыми вы, вероятно, сталкивались в Android:printf(String format, Obj... args)или execute(Params... params) из AsyncTask.

Для начала разберем основы vararg и оператора spread, а затем подробно рассмотрим несколько сценариев, анализируя, что происходит за кадром.

vararg в Kotlin

Kotlin поддерживает объявление функции с переменным числом аргументов. Достаточно поставить перед названием параметра модификатор vararg: fun format(format: String, vararg args: Any).

Несколько правил касательно vararg

В Java параметр vararg должен быть последним в списке параметров — поэтому параметр vararg может быть только один. В Kotlin vararg не обязательно должен занимать последнее место в списке, однако использование нескольких параметров vararg все же недопустимо.

Рассмотрим декомпилированный исходный код Java при объявлении параметров vararg.

Параметр vararg в качестве последнего в списке

Объявление параметра vararg в качестве последнего в списке в функции Kotlin выглядит следующим образом:

fun format(format: String, vararg params: String)

во время компиляции в соответствующий код Java:

void format(@NotNull String format, @NotNull String... params)

Объявление параметров после vararg

Параметр vararg не является последним в списке:

fun format(format: String, vararg params: String, encoding: String)

при компиляции в соответствующий код Java:

void format(String format, String[] params, String encoding)

Вывод: если vararg не является последним параметром, то он компилируется в качестве массива типа parameter.

Оператор Spread

“Вау!? В Kotlin есть указатели?” — моя первая реакция при виде подобной функции вKotlin: format(output, *params). 
Нет, это не указатель. Это spread — оператор, который распаковывает массив в список значений из этого массива. Он нужен при передаче массива в качестве параметра vararg.

При вызове функции format , определенной следующим образом:

val params = arrayOf("param1", "param2")
format(output, params)

происходит ошибка компиляции Type mismatch: inferred type is Array<String> but String was expected.

Для того, чтобы ее исправить, нужно использовать оператор spread для распаковки массива параметров в соответствующие значения: format(output, *params)

Рассмотрим соответствующий декомпилированный код Java:

String[] params = new String[]{"param1", "param2"};
format(output,
(String[])Arrays.copyOf(params, params.length));

Объединение значений spread

При использовании оператора spread можно передать дополнительные значения в параметр vararg или даже объединить несколько массивов spread в одном параметре:

-2

Рассмотрим определение arrayOf():

public inline fun <reified @PureReifiable T> arrayOf(vararg elements: T): Array<T>

Это означает, что оператор spread можно использовать для объединения массивов в новый массив:

-3

Вывод: во время объединения значений spread в параметр vararg, за кадром используется SpreadBuilder для сбора всех значений. Затем SpreadBuilder конвертируется в массив при вызове функции.

Мы разобрали, как Kotlin обрабатывает параметры vararg, и как выглядит соответствующий код Java при объявлении и вызове подобных функций.

Читайте нас в телеграмме и vk

Перевод статьи Tibi Csabai: Kotlin’s vararg and spread operator