Opérateur d'astérisque de Kotlin avant le nom de variable ou opérateur de propagation dans Kotlin

97

Je veux savoir ce que fait exactement l'astérisque avant le nom de la variable dans Kotlin. J'ai vu ceci ( *args) à l' exemple de 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)
}
mojtab23
la source

Réponses:

163

L' *opérateur est connu sous le nom d' opérateur de propagation à Kotlin.

À partir de la référence Kotlin ...

Lorsque nous appelons une fonction vararg, nous pouvons passer des arguments un par un, par exemple asList (1, 2, 3), ou, si nous avons déjà un tableau et que nous voulons passer son contenu à la fonction, nous utilisons le spread opérateur (préfixez le tableau avec *):

Il peut être appliqué à un tableau avant de le passer dans une fonction qui accepte varargs.

Par exemple...

Si vous avez une fonction qui accepte un nombre varié d'arguments ...

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

Vous pouvez y passer un tableau comme ça ...

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

Remarques:

  • L' *opérateur est également l' opérateur de multiplication (bien sûr).
  • L'opérateur ne peut être utilisé que lors du passage d'arguments à une fonction. Le résultat de l'opération ne peut pas être stocké car il ne donne aucune valeur (il s'agit d' un sucre purement syntaxique).
  • L'opérateur peut confondre certains programmeurs C / C ++ au début car il semble qu'un pointeur est en cours de dé-référencé. Ce n'est pas le cas; Kotlin n'a aucune notion de pointeurs .
  • L'opérateur peut être utilisé entre d'autres arguments lors de l'appel d'une fonction vararg. Ceci est démontré dans l'exemple ici .
  • L'opérateur est similaire à la applyfonction dans divers langages de programmation fonctionnelle.
Byxor
la source
Le tableau en ligne de l'opérateur Spread est-il? Par exemple, pour le tableau a = [1, 2, 3] funWithVararg (* a) s'inscrit dans funWithVararg (1,2,3)? Je veux dire au niveau du bytecode.
David
22

En plus des réponses qui étaient directement vers "c'est quoi ce truc!?!", Vous avez souvent le cas où vous avez un Listet que vous voulez le passer à une fonction qui attend un vararg. Pour cela, la conversion est:

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

En supposant que le dernier paramètre de someFuncest varargdu même type que les éléments de la liste.

Jayson Minard
la source
Merci beaucoup! Cela devrait être dans les documents officiels sous la section des opérateurs de diffusion comme quelque chose à surveiller lorsque votre opérateur de diffusion ne fonctionne pas.
happyesktop
Merci! Vraiment utile. Vous vous demandez ce qu'est "Spread Operator" dans les coulisses? Est-ce juste un moyen d'obtenir une valeur varargs?
Nicolas Jafelle
11

Comme décrit dans la documentation, il s'agit d'un opérateur de propagation:

Lorsque nous appelons une fonction vararg, nous pouvons passer des arguments un par un, par exemple asList (1, 2, 3), ou, si nous avons déjà un tableau et que nous voulons passer son contenu à la fonction, nous utilisons le spread opérateur (préfixez le tableau avec *):

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

Si une fonction qui accepte un paramètre vararg (nombre variable d'arguments) comme:

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

Maintenant, pour appeler cette méthode, nous pouvons faire:

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

Mais que faire si nous avons ces valeurs dans un tableau, comme:

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

puis, pour appeler cette méthode, nous devons utiliser l'opérateur de propagation, comme:

 sum(*array)

Ici, * (opérateur de diffusion) passera tout le contenu de ce tableau.

* tableau équivaut à 1,2,3,4,5

Mais attendez une minute, que se passe-t-il si nous l'appelons comme ceci: sum(array) cela nous donnera une erreur de compilation de type Mismatch:

Type mismatch.
Required:Int
Found:IntArray

Le problème est que la sumfonction accepte un vararg Intparamètre (qui accepte une valeur comme: 1,2,3,4,5) et si nous transmettons un tableau, il sera passé comme IntArray.

Suraj Vaishnav
la source
4

En Java, vous pouvez transmettre un tableau tel quel, mais un avantage de décompresser un tableau avec l'opérateur de propagation *est que l'opérateur de propagation vous permet de combiner les valeurs d'un tableau et certaines valeurs fixes en un seul appel. Java ne prend pas en charge cela.

Gulzar Bhat
la source
J'ai voté pour, parce que je me suis demandé pourquoi ils l'ont implémenté comme ça. Je n'en suis toujours pas sûr à 100%. Je veux dire, ne pouvaient-ils pas simplement déduire cela dans la plupart des cas?
Tim Büthe
1
@ TimBüthe Dans certains cas, il ne serait pas possible de le déduire, considérons les cas suivants val resultOne = arrayOf(intArrayOne, intArrayTwo)et val resultTwo = arrayOf(*intArrayOne, *intArrayTwo). Type de resultOneet resultTwosont respectivement Array<Int>et Array<Array<Int>>. Je crois que c'est l'une des raisons
Farid