Operator gwiazdki Kotlin przed nazwą zmiennej lub operator spreadu w Kotlinie

101

Chcę wiedzieć, co dokładnie robi gwiazdka przed nazwą zmiennej w Kotlinie. Widziałem to ( *args) w przykładzie 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
źródło

Odpowiedzi:

168

The * operator is known as the Spread Operator in Kotlin.

From the Kotlin Reference...

When we call a vararg-function, we can pass arguments one-by-one, e.g. asList(1, 2, 3), or, if we already have an array and want to pass its contents to the function, we use the spread operator (prefix the array with *):

It can be applied to an Array before passing it into a function that accepts varargs.

For Example...

If you have a function that accepts a varied number of arguments...

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

You can pass an array into it like so...

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

Notes:

  • The * operator is also the multiplication operator (of course).
  • The operator can only be used when passing arguments to a function. The result of the operation cannot be stored since it yields no value (it is purely syntactic sugar).
  • The operator may confuse some C/C++ programmers at first because it looks like a pointer is being de-referenced. It isn't; Kotlin has no notion of pointers.
  • The operator can be used in-between other arguments when calling a vararg function. This is demonstrated in the example here.
  • The operator is similar to the apply function in various functional programming languages.
byxor
źródło
Is Spread operator inline array? For example for array a = [1, 2, 3] funWithVararg(*a) inlines into funWithVararg(1,2,3)? I mean in bytecode level.
David
23

In addition to the answers that were directly towards "what is this thing!?!", you often have the case where you have a List and want to pass it to a function that is expecting a vararg. For this, the conversion is:

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

Assuming that last parameter of someFunc is vararg of the same type as the elements in the list.

Jayson Minard
źródło
Thank you so much! This should be in the official docs under the spread operator section as something to watch out for when your spread operator is not working.
pleasedesktop
Thanks! Really helpfull. Wondering what is "Spread Operator" behind the scenes? Is just a way to get a varargs value?
Nicolas Jafelle
11

As described in the documentation this is a spread operator:

When we call a vararg-function, we can pass arguments one-by-one, e.g. asList(1, 2, 3), or, if we already have an array and want to pass its contents to the function, we use the spread operator (prefix the array with *):

val a = arrayOf(1, 2, 3) 
val list = asList(-1, 0, *a, 4)
miensol
źródło
6

If a function which accept a vararg(Variable number of arguments) parameter like:

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

Now to call this method, we can do:

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

But what if we have these value in an array, like:

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

then, to call this method we have to use spread operator, like:

 sum(*array)

Here, *(spread operator) will pass all content of that array.

*array is equivalent to 1,2,3,4,5

But wait a minute, what if we call it like this: sum(array) it will give us Type Mismatch compile time error:

Type mismatch.
Required:Int
Found:IntArray

The problem is sum function accept a vararg Int parameter(which accept value like: 1,2,3,4,5) and if we pass array, it will be passed as IntArray.

Suraj Vaishnav
źródło
5

In Java you can pass an array as is but an advantage of unpacking an array with spread operator * is that spread operator lets you combine the values from an array and some fixed values in a single call. Java doesn't support this.

Gulzar Bhat
źródło
1
Upvoted, because I asked myself why they implemented it like this. I'm still not 100% sure about it. I mean, couldn't they just infer this in most cases?
Tim Büthe
1
@TimBüthe In some cases, it wouldn't be possible to infer it, consider the following cases val resultOne = arrayOf(intArrayOne, intArrayTwo) and val resultTwo = arrayOf(*intArrayOne, *intArrayTwo). Type of resultOne and resultTwo are respectively Array<Int> and Array<Array<Int>>. I beleive that's one of the reasons
Farid