vararg Arguments

varargs allow flexibly-sized argument lists.

The Lists atom introduced listOf(), which takes any number of arguments and produces a List:

// Varargs/ListOf.kt import atomictest.eq fun main(args: Array<String>) { listOf(1) eq "[1]" listOf("a", "b") eq "[a, b]" }

Using the vararg keyword, you can define a function that works just like listOf(): it can take any number of arguments. vararg is short for variable argument list:

// Varargs/VariableArgLists.kt fun v(s: String, vararg d: Double) {} fun main(args: Array<String>) { v("abc", 1.0, 2.0, 3.0, 4.0) }

A function definition may specify only one argument as vararg. Although it’s possible to specify any item in the argument list as vararg, it’s usually simplest to do it for the last one.

vararg allows you to pass any number (including zero) of arguments of the specified type. The vararg arguments are accessed using the argument name, which becomes an Array:

// Varargs/VarargSum.kt import atomictest.eq fun sum(vararg numbers: Int): Int { var total = 0 for (n in numbers) total += n return total } fun main(args: Array<String>) { sum(13, 27, 44) eq 84 sum(1, 3, 5, 7, 9, 11) eq 36 sum() eq 0 }

We’ve been using Array throughout the book because it’s part of the standard way to define main(). Arrays and Lists have very similar interfaces, but are implemented differently—List is a regular library class while Array has special low-level support. In day-to-day programming, you’ll just use a List whenever you need a simple sequence; Array is used mainly in mixed Kotlin and Java projects, when Java code expects or returns Arrays.

Because List and Array are very similar, in most cases you can just ignore the fact that vararg produces an Array and just treat it as if it were a List:

// Varargs/VarargLikeList.kt fun checkOperations(vararg ints: Int) { println("Size: ${ints.size}") println("Sum: ${ints.sum()}") println("Min: ${ints.min()}") println("Max: ${ints.max()}") println("Average: ${ints.average()}") } fun main(args: Array<String>) { checkOperations(10, -3, 8, 1, 9) } /* Output: Size: 5 Sum: 25 Min: -3 Max: 10 Average: 5.0 */

You can pass an Array of elements wherever a vararg is accepted. To create an array, use arrayOf() in the same way you use listOf(). Note that an Array is always mutable. To convert an Array into a sequence of arguments (not just a single element of type Array), use the spread operator, *:

// Varargs/SpreadOperator.kt import atomictest.eq fun main(args: Array<String>) { val array = intArrayOf(4, 5) sum(1, 2, 3, *array, 6) eq 21 // [1] // Won't compile: // sum(1, 2, 3, array, 6) val list = listOf(9, 10, 11) sum(*list.toIntArray()) eq 30 // [2] }

If you pass an array of primitive types (like Int, Double or Boolean) as in the example above, the Array creation function must be specifically typed. If you choose arrayOf(4, 5) instead of intArrayOf(4, 5), the line [1] will produce an error complaining that inferred type is Array but IntArray was expected.

The spread operator only works with arrays. If you have a List that you want to pass as a sequence of arguments, first convert it to an array and then apply the spread operator, as in [2]. Because the result is an array of a primitive type, we must again use the specific conversion function toIntArray().

The spread operator is especially helpful when you must pass vararg arguments to another function that also expects varargs:

// Varargs/TwoFunctionsWithVarargs.kt fun first(vararg numbers: Int) { for (i in numbers) { print("[$i]") } } fun second(vararg numbers: Int) = first(*numbers) fun main(args: Array<String>) { second(7, 9, 32) } /* Output: [7][9][32] */
List and Array appear to have similar functionality—why are there two types? This comes from Kotlin’s requirement of compatibility with other languages, Java in particular. Choose Lists by default when you need a sequence of elements. Use Arrays only when a third-party API requests an Array from you, or you’re dealing with varargs.

Previous          Next

©2018 Mindview LLC. All Rights Reserved.