Operatore asterisco di Kotlin prima del nome della variabile o Operatore di diffusione in Kotlin


97

Voglio sapere cosa fa esattamente l'asterisco prima del nome della variabile in Kotlin. Ho visto questo ( *args) nell'esempio di 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)
}

Risposte:


164

L' *operatore è noto come Spread Operator in Kotlin.

Dal riferimento di Kotlin ...

Quando chiamiamo una funzione vararg, possiamo passare gli argomenti uno per uno, ad esempio asList (1, 2, 3), oppure, se abbiamo già un array e vogliamo passare il suo contenuto alla funzione, usiamo lo spread operatore (anteponi l'array con *):

Può essere applicato a un array prima di passarlo a una funzione che accetta varargs.

Per esempio...

Se hai una funzione che accetta un numero variabile di argomenti ...

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

Puoi passarci un array in questo modo ...

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

Appunti:

  • L' *operatore è anche l' operatore di moltiplicazione (ovviamente).
  • L'operatore può essere utilizzato solo quando si passano argomenti a una funzione. Il risultato dell'operazione non è memorizzabile in quanto non da valore (è puramente zucchero sintattico).
  • All'inizio l'operatore potrebbe confondere alcuni programmatori C / C ++ perché sembra che venga de-referenziato un puntatore. Non lo è; Kotlin non ha la nozione di puntatori .
  • L'operatore può essere utilizzato tra altri argomenti quando si chiama una funzione vararg. Questo è dimostrato nell'esempio qui .
  • L'operatore è simile alla applyfunzione in vari linguaggi di programmazione funzionale.

Spread operator inline array? Ad esempio per array a = [1, 2, 3] funWithVararg (* a) inline in funWithVararg (1,2,3)? Intendo a livello di bytecode.
David

22

Oltre alle risposte che erano direttamente verso "cos'è questa cosa!?!", Spesso hai il caso in cui hai un Liste vuoi passarlo a una funzione che si aspetta a vararg. Per questo, la conversione è:

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

Supponendo che l'ultimo parametro di someFuncsia varargdello stesso tipo degli elementi nell'elenco.


Grazie mille! Questo dovrebbe essere nei documenti ufficiali nella sezione operatore di diffusione come qualcosa a cui prestare attenzione quando il tuo operatore di diffusione non funziona.
pleasedesktop

Grazie! Davvero utile. Ti chiedi cosa sia "Spread Operator" dietro le quinte? È solo un modo per ottenere un valore varargs?
Nicolas Jafelle

11

Come descritto nella documentazione questo è un operatore spread:

Quando chiamiamo una funzione vararg, possiamo passare gli argomenti uno per uno, ad esempio asList (1, 2, 3), oppure, se abbiamo già un array e vogliamo passare il suo contenuto alla funzione, usiamo lo spread operatore (anteponi l'array con *):

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

6

Se una funzione che accetta un parametro vararg (numero variabile di argomenti) come:

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

Ora per chiamare questo metodo, possiamo fare:

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

Ma cosa succede se abbiamo questi valori in un array, come:

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

quindi, per chiamare questo metodo dobbiamo usare l'operatore spread, come:

 sum(*array)

Qui, * (operatore di diffusione) passerà tutto il contenuto di quell'array.

* array è equivalente a 1,2,3,4,5

Ma aspetta un minuto, cosa succede se lo chiamiamo così: sum(array) ci darà l'errore di compilazione Type Mismatch:

Type mismatch.
Required:Int
Found:IntArray

Il problema è che la sumfunzione accetta un vararg Intparametro (che accetta valori come: 1,2,3,4,5) e se passiamo array, verrà passato come IntArray.


5

In Java è possibile passare un array così com'è, ma un vantaggio di decomprimere un array con l'operatore spread *è che l'operatore spread ti consente di combinare i valori di un array e alcuni valori fissi in una singola chiamata. Java non lo supporta.


1
Votato, perché mi sono chiesto perché l'hanno implementato in questo modo. Non ne sono ancora sicuro al 100%. Voglio dire, non potrebbero semplicemente dedurlo nella maggior parte dei casi?
Tim Büthe

1
@ TimBüthe In alcuni casi non sarebbe possibile dedurlo, considera i seguenti casi val resultOne = arrayOf(intArrayOne, intArrayTwo)e val resultTwo = arrayOf(*intArrayOne, *intArrayTwo). Tipo di resultOnee resultTwosono rispettivamente Array<Int>e Array<Array<Int>>. Credo che sia uno dei motivi
Farid
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.