Оператор зірочки Kotlin перед ім'ям змінної або оператором поширення в Kotlin


97

Я хочу знати, що саме робить зірочка перед назвою змінної в 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)
}

Відповіді:


163

*Оператор відомий як спред оператора в Котлин.

З посилання на 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функції в різних мовах функціонального програмування.

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

22

На додаток до відповідей, які безпосередньо стосувались "що це за штука!?!", У вас часто трапляється той випадок, коли у вас є a, Listі ви хочете передати його функції, яка очікує a vararg. Для цього перетворення:

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

Припускаючи, що останній параметр someFuncмає varargтой самий тип, що і елементи у списку.


Дуже дякую! Це повинно бути в офіційних документах у розділі оператора розповсюдження, як чогось, на що слід звертати увагу, коли ваш оператор розповсюдження не працює.
— gladesktop

Дякую! Дійсно корисно. Цікаво, що таке "оператор розповсюдження" за лаштунками? Це просто спосіб отримати значення varargs?
— Nicolas Jafelle

11

Як описано в документації, це оператор поширення:

Коли ми викликаємо функцію vararg, ми можемо передавати аргументи по одному, наприклад, asList (1, 2, 3), або, якщо ми вже маємо масив і хочемо передати його вміст функції, ми використовуємо розповсюдження оператор (префікс масиву *):

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

5

Якщо функція, яка приймає параметр 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.


4

У Java ви можете передавати масив як є, але перевага розпакування масиву за допомогою оператора розповсюдження *полягає в тому, що оператор поширення дозволяє поєднувати значення з масиву та деякі фіксовані значення в одному виклику. Java цього не підтримує.


Проголосував, бо я запитав себе, чому вони це реалізували так. Я все ще не впевнений у цьому на 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.