Оператор звездочки в Kotlin перед именем переменной или оператор распространения в Kotlin


102

Я хочу знать, что именно делает звездочка перед именем переменной в Kotlin. Я видел это ( *args) в примере Spring boot Kotlin :

@SpringBootApplication
open class Application {

    @Bean
    open fun init(repository: CustomerRepository) = CommandLineRunner {
        repository.save(Customer("Jack", "Bauer"))
        repository.save(Customer("Chloe", "O'Brian"))
        repository.save(Customer("Kim", "Bauer"))
        repository.save(Customer("David", "Palmer"))
        repository.save(Customer("Michelle", "Dessler"))
    }
}

fun main(args: Array<String>) {
    SpringApplication.run(Application::class.java, *args)
}

Ответы:


169

Этот *оператор известен в Котлине как оператор распространения .

Из справочника Kotlin ...

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

Его можно применить к массиву перед передачей в функцию, которая принимает varargs.

Например...

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

fun sumOfNumbers(vararg numbers: Int): Int {
    return numbers.sum()
}

Вы можете передать в него массив так ...

val numbers = intArrayOf(2, 3, 4)
val sum = sumOfNumbers(*numbers)
println(sum) // Prints '9'

Примечания:

  • *Оператор также оператор умножения (конечно).
  • Оператор можно использовать только при передаче аргументов функции. Результат операции не может быть сохранен, поскольку он не дает никакого значения (это чисто синтаксический сахар).
  • Оператор может сначала сбить с толку некоторых программистов C / C ++, потому что похоже, что ссылка на указатель отменяется. Это не так; Котлин не знает указателей .
  • Оператор может использоваться между другими аргументами при вызове функции vararg. Это продемонстрировано на примере здесь .
  • Оператор аналогичен applyфункции в различных языках функционального программирования.

Является ли встроенный массив оператора распространения? Например, для массива a = [1, 2, 3] funWithVararg (* a) встраивается в funWithVararg (1,2,3)? Я имею в виду на уровне байт-кода.
Дэвид

23

В дополнение к ответам, которые относились непосредственно к «что это за штука!?!», Вы часто имеете дело с тем, что у вас есть Listи вы хотите передать его функции, ожидающей vararg. Для этого преобразование:

someFunc(x, y, *myList.toTypedArray())

Предполагая, что последний параметр someFuncимеет varargтот же тип, что и элементы в списке.


Спасибо огромное! Это должно быть в официальной документации в разделе оператора распространения, чтобы следить за тем, когда ваш оператор распространения не работает.
pleasedesktop

Благодарность! Действительно полезно. Хотите знать, что такое «Оператор распространения» за кулисами? Это просто способ получить значение varargs?
Nicolas Jafelle

11

Как описано в документации, это оператор распространения:

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

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

6

Если функция, которая принимает параметр vararg (переменное количество аргументов), например:

fun sum(vararg data:Int)
{
   // function body here         
}

Теперь, чтобы вызвать этот метод, мы можем:

sum(1,2,3,4,5)

Но что, если у нас есть эти значения в массиве, например:

val array= intArrayOf(1,2,3,4,5)

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

 sum(*array)

Здесь * (оператор распространения) передаст все содержимое этого массива.

* массив эквивалентен 1,2,3,4,5

Но подождите, а что, если мы назовем это так: sum(array) это даст нам ошибку времени компиляции Type Mismatch:

Type mismatch.
Required:Int
Found:IntArray

Проблема в том, что sumфункция принимает vararg Intпараметр (который принимает значение, например: 1,2,3,4,5), и если мы передадим массив, он будет передан как IntArray.


5

В Java вы можете передавать массив как есть, но преимущество распаковки массива с оператором распространения *заключается в том, что оператор распространения позволяет вам комбинировать значения из массива и некоторые фиксированные значения за один вызов. Java этого не поддерживает.


1
Проголосовали, потому что я спрашивал себя, почему они так это реализовали. Я до сих пор не уверен в этом на 100%. Я имею в виду, не могли ли они просто сделать это в большинстве случаев?
Тим Бют

1
@ TimBüthe В некоторых случаях это невозможно сделать, рассмотрим следующие случаи val resultOne = arrayOf(intArrayOne, intArrayTwo)и val resultTwo = arrayOf(*intArrayOne, *intArrayTwo). Типа resultOneи resultTwoявляются соответственно Array<Int>и Array<Array<Int>>. Я верю, что это одна из причин
Фарид
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.