Variadic parameters
A parameter written ...name collects every remaining positional argument into a List, and a collection is only unpacked into it when the call spreads it with the same three dots.
Diese Seite gibt es noch nicht auf Deutsch, deshalb steht sie hier auf Englisch. Zur englischen Seite
A variadic parameter, written ...name: Type, takes any number of positional arguments of Type and collects them
into a List<Type>. A caller who already holds a collection spreads it into the call with the same ....
Example#
fn sumAll(...numbers: Int): Int {
numbers.fold 0 { a, b => a + b }
}
const values = [1, 2, 3]
print sumAll(1, 2, 3)
print sumAll(...values)Syntax#
fn <name>(..., ...<name>: <Type>): <ReturnType> { ... }
<call>(..., ...<expression>)Rules#
...name: Typeinside a parameter list declares a variadic parameter, and its body seesnameas aList<Type>. It is written last, and every positional argument from its position onward fills it.A call spreads an
Iterate<Type>into a variadic parameter with...expression. Spreading works with any type that implements theIteratetrait, not onlyList, so aSetspreads the same way aListdoes.fn sumAll(...numbers: Int): Int { numbers.fold 0 { a, b => a + b } } const someSet = Set.of 4, 5, 6 print sumAll(1, ...someSet)...only fills a variadic parameter: spreading into an ordinary one is rejected, naming the parameter it was aimed at.Kompiliert nichtfn configure(port: Int) { print port } const settings = [8080] configure(...settings) // error: `port` is not a variadic parameter, so `...` cannot spread into itA variadic parameter that receives no argument becomes an empty list, not a missing-argument error.
fn sumAll(...numbers: Int): Int { numbers.fold 0 { a, b => a + b } } print sumAll()A parameter declared after a variadic one can only be filled by label. Every positional argument from the variadic parameter's position onward fills it, so a later parameter is never reached positionally.
Kompiliert nichtfn describe(...numbers: Int, label: String): String { "{label}: {numbers}" } print describe(1, 2, "totals") // error: `describe` has no argument for `label` // error: Expected `Int64`, found `String`
What this is not#
A collection is not unpacked by standing in a positional argument on its own. Only ... unpacks it; without it,
the whole collection becomes the one element the variadic parameter collects.
fn sumAll(...numbers: Int): Int {
numbers.fold 0 { a, b => a + b }
}
const values = [1, 2, 3]
print sumAll(...values)fn wrapped(...numbers: List<Int>): List<List<Int>> {
numbers
}
const values = [1, 2, 3]
print wrapped(values)The second program is not an error - it type checks, because values is one argument of type List<Int> and the
parameter's element type is List<Int> too. Its result is [[1, 2, 3]], a list of one list, which is rarely what was
meant. Spreading (...values) is what turns the collection's own elements into the arguments.
...rest is not *args from a language with no other way to pass many arguments. Every parameter before it is
still ordinary and still labelled the same way, and only the first variadic parameter of a signature can ever collect
anything positionally (see rule 4).
Related#
- Arguments and labels - how a positional argument is matched to a parameter.
- Declaring a function - the rest of the parameter list.