Operador de asterisco Kotlin antes do nome da variável ou Operador Spread em Kotlin

97

Eu quero saber exatamente o que o asterisco faz antes do nome da variável em Kotlin. Eu vi este ( *args) no exemplo do 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
fonte

Respostas:

161

O *operador é conhecido como Spread Operator em Kotlin.

Da Referência de Kotlin ...

Quando chamamos uma função vararg, podemos passar os argumentos um por um, por exemplo, asList (1, 2, 3), ou, se já tivermos um array e quisermos passar seu conteúdo para a função, usamos o spread operador (prefixe a matriz com *):

Ele pode ser aplicado a um Array antes de transmiti-lo a uma função que o aceita varargs.

Por exemplo...

Se você tem uma função que aceita um número variado de argumentos ...

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

Você pode passar um array para ele assim ...

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

Notas:

  • O *operador também é o operador de multiplicação (é claro).
  • O operador só pode ser usado ao passar argumentos para uma função. O resultado da operação não pode ser armazenado, pois não produz nenhum valor (é um açúcar puramente sintático).
  • O operador pode confundir alguns programadores C / C ++ no início porque parece que um ponteiro está sendo desreferenciado. Não é; Kotlin não tem noção de ponteiros .
  • O operador pode ser usado entre outros argumentos ao chamar uma função vararg. Isso é demonstrado no exemplo aqui .
  • O operador é semelhante à applyfunção em várias linguagens de programação funcionais.
Byxor
fonte
O Spread operator inline array? Por exemplo, para a matriz a = [1, 2, 3] funWithVarg (* a) alinhada em funWithVararg (1,2,3)? Quero dizer, em nível de bytecode.
David
22

Além das respostas diretas para "o que é essa coisa!?!", Você costuma ter o caso em que tem um Liste deseja passá-lo para uma função que está esperando um vararg. Para isso, a conversão é:

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

Supondo que o último parâmetro de someFuncseja varargdo mesmo tipo que os elementos da lista.

Jayson Minard
fonte
Muito obrigado! Isso deve estar nos documentos oficiais na seção do operador de spread como algo a observar quando o seu operador de spread não está funcionando.
happyesktop
Obrigado! Realmente útil. Quer saber o que é "Spread Operator" nos bastidores? É apenas uma maneira de obter um valor de varargs?
Nicolas Jafelle
11

Conforme descrito na documentação, este é um operador de propagação:

Quando chamamos uma função vararg, podemos passar os argumentos um por um, por exemplo, asList (1, 2, 3), ou, se já tivermos um array e quisermos passar seu conteúdo para a função, usamos o spread operador (prefixe a matriz com *):

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

Se uma função que aceita um parâmetro vararg (número variável de argumentos) como:

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

Agora, para chamar esse método, podemos fazer:

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

Mas e se tivermos esses valores em uma matriz, como:

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

então, para chamar este método, temos que usar o operador spread, como:

 sum(*array)

Aqui, * (operador de propagação) passará todo o conteúdo desse array.

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

Mas espere um minuto, e se chamarmos assim: sum(array) isso nos dará erro de tempo de compilação de incompatibilidade de tipo:

Type mismatch.
Required:Int
Found:IntArray

O problema é que a sumfunção aceita um vararg Intparâmetro (que aceita valores como: 1,2,3,4,5) e se passarmos array, ele será passado como IntArray.

Suraj Vaishnav
fonte
4

Em Java, você pode passar um array como está, mas uma vantagem de desempacotar um array com o operador spread *é que o operador spread permite combinar os valores de um array e alguns valores fixos em uma única chamada. Java não suporta isso.

Gulzar Bhat
fonte
Votei positivamente porque me perguntei por que eles o implementaram dessa forma. Ainda não estou 100% certo disso. Quer dizer, eles não podiam simplesmente inferir isso na maioria dos casos?
Tim Büthe de
1
@ TimBüthe Em alguns casos, não seria possível inferir, considere os seguintes casos val resultOne = arrayOf(intArrayOne, intArrayTwo)e val resultTwo = arrayOf(*intArrayOne, *intArrayTwo). Os tipos de resultOnee resultTwosão respectivamente Array<Int>e Array<Array<Int>>. Eu acredito que esse é um dos motivos
Farid,