How to pass vararg as array to function in Kotlin?

2020-08-14 05:52发布

问题:

I want to pass vararg from the buy function to the drive function but I get

a compile error:

required Array<T> found Array<out T>

code:

class Car

fun buy(vararg cars: Car) {
    drive(cars) //compile error
}

fun drive(cars: Array<Car>) {
    //...
}

回答1:

Another solution would be to change drive to fun drive(Array<out Car>) { ... }. This of course means that the cars inside drive cannot be modified but avoids the copying.



回答2:

The precise error is:

Type mismatch.
Required: Array<Car>
Found:    Array<out Car>

The problem is that when you have a vararg cars: Car function parameter, its type inside the function is Array<out Car>, which basically represents a read-only array of the arguments the function was called with - after all, it wouldn't really be a nice thing to start modifying the arguments you got as a vararg (function parameters in Kotlin are read-only vals, and this is something very similar).

But your drive function requires a regular Array<Car>, which of course is writable as well. So if you wish to keep these function signatures, you'll need to create a new array that contains everything from your read-only array. This can be created using the following syntax:

drive(arrayOf(*cars))

This calls the arrayOf function we usually create arrays with, which takes a vararg parameter, and uses the spread operator which is a way to pass in the elements of an array (which cars is, inside the buy function) as the vararg parameters (docs here).

While all this may sound complicated, it's actually a very efficient solution, as it just uses Array.copyOf under the hood in the bytecode.



回答3:

Essencially you need the vararg keywork before the variable name.

fun args(vararg cars: Car) {
   //use cars as an array 
}


回答4:

override fun checkMatch(vararg cards: SetsCard): Int {
    return if (isSet(*cards)) 16 else -2
}

private fun isSet(vararg cards: SetsCard) : Boolean {
    if (cards.size == 3) {
        return true
    }
    return false
}