Оператор звездочки в 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.