Kotlin: Можете ли вы использовать именованные аргументы для varargs?

Например, у вас может быть функция со сложной сигнатурой и varargs:

fun complicated(easy: Boolean = false, hard: Boolean = true, vararg numbers: Int)

Было бы разумно, что вы должны иметь возможность вызвать эту функцию следующим образом:

complicated(numbers = 1, 2, 3, 4, 5)

К сожалению, компилятор этого не допускает.

Можно ли использовать именованные аргументы для varargs? Есть ли какие-нибудь умные способы обхода?

Ответ 1

Его можно обойти, переместив необязательные аргументы после vararg:

fun complicated(vararg numbers: Int, easy: Boolean = false, hard: Boolean = true) = {}

Тогда его можно назвать следующим:

complicated(1, 2, 3, 4, 5)
complicated(1, 2, 3, hard = true)
complicated(1, easy = true)

Обратите внимание, что завершающие необязательные параметры должны всегда передаваться с именем. Это не скомпилируется:

complicated(1, 2, 3, 4, true, true) // compile error

Другим вариантом является vararg сахара vararg для явного массива param:

fun complicated(easy: Boolean = false, hard: Boolean = true, numbers: IntArray) = {}

complicated(numbers = intArrayOf(1, 2, 3, 4, 5))

Ответ 2

Чтобы передать именованный аргумент параметру vararg, используйте оператор spread:

complicated(numbers = *intArrayOf(1, 2, 3, 4, 5))

Ответ 3

Kotlin Docs четко говорит, что:

Переменная количество аргументов (Varargs)

Параметр функции (обычно последний) может быть отмечен модификатором vararg:

fun <T> asList(vararg ts: T): List<T> {
  val result = ArrayList<T>()
  for (t in ts) // ts is an Array
    result.add(t)
  return result
}

позволяя передать переменное количество аргументов функции:

  val list = asList(1, 2, 3)

Внутри функции vararg -parameter типа T видна как массив из T, т. ts Переменная ts в приведенном выше примере имеет тип Array<out T>.

Только один параметр может быть отмечен как vararg. Если параметр vararg не является последним в списке, значения для следующих параметров могут быть переданы с использованием синтаксиса с именованным аргументом или, если параметр имеет тип функции, передавая лямбду вне круглых скобок.

Когда мы вызываем vararg -function, мы можем передавать аргументы один за другим, например asList(1, 2, 3), или, если мы уже имеем массив и хотим передать его содержимое функции, мы используем распространение оператора (префикс массив с *):

val a = arrayOf(1, 2, 3)
val list = asList(-1, 0, *a, 4)

От: https://kotlinlang.org/docs/reference/functions.html#variable-number-of-arguments-varargs

Чтобы возобновить работу, вы можете сделать это с помощью оператора спредов, чтобы он выглядел так:

complicated(numbers = *intArrayOf(1, 2, 3, 4, 5))

Надеюсь, это поможет

Ответ 4

Параметр vararg может быть в любом месте в списке параметров. См. Пример ниже о том, как его можно вызывать с помощью различного набора параметров. BTW любой вызов также может обеспечить лямбда после закрытых круглых скобок.

fun varargs(
  first: Double = 0.0,
  second: String = "2nd",
  vararg varargs: Int,
  third: String = "3rd",
  lambda: ()->Unit = {}
) {
  ...
}

fun main(args: Array<String>) {
  val list = intArrayOf(1, 2, 3)

  varargs(1.0, "...", *list, third="third")
  varargs(1.0, "...", *list)
  varargs(1.0, varargs= *list, third="third")
  varargs(varargs= *list, third="third")
  varargs(varargs= *list, third="third", second="...")
  varargs(varargs= *list, second="...")

  varargs(1.0, "...", 1, 2, 3, third="third")
  varargs(1.0, "...", 1, 2, 3)
  varargs(1.0)

  varargs(1.0, "...", third="third")
  varargs(1.0, third="third")
  varargs(third="third")
}