This is an excerpt from the Scala Cookbook (partially modified for the internet). This is Recipe 5.7, “How to Scala create methods that take variable-arguments (varargs) fields.”
Problem
To make a Scala method more flexible, you want to define a method parameter that can take a variable number of arguments, i.e., a varargs field.
Solution
Define a varargs field in your method declaration by adding a * character after the field type:
def printAll(strings: String*) {
strings.foreach(println)
}
Given that method declaration, the printAll method can be called with zero or more parameters:
// these all work
printAll()
printAll("foo")
printAll("foo", "bar")
printAll("foo", "bar", "baz")
Use _* to adapt a sequence
As shown in the following example, you can use Scala’s _* operator to adapt a sequence (Array, List, Seq, Vector, etc.) so it can be used as an argument for a varargs field:
// a sequence of strings
val fruits = List("apple", "banana", "cherry")
// pass the sequence to the varargs field
printAll(fruits: _*)
If you come from a Unix background, it may be helpful to think of _* as a “splat” operator. This operator tells the compiler to pass each element of the sequence to printAll as a separate argument, instead of passing fruits as a single argument.
This is also similar to using
xargson the Unix/Linux command line.
Discussion
When declaring that a method has a field that can contain a variable number of arguments, the varargs field must be the last field in the method signature. Attempting to define a field in a method signature after a varargs field is an error:
scala> def printAll(strings: String*, i: Int) {
| strings.foreach(println)
| }
<console>:7: error: *-parameter must come last
def printAll(strings: String*, i: Int) {
^
As an implication of that rule, a method can have only one varargs field.
As demonstrated in the Solution, if a field is a varargs field, you don’t have to supply any arguments for it. For instance, in a method that has only one varargs field, you can call it with no arguments:
scala> def printAll(numbers: Int*) {
| numbers.foreach(println)
| }
printAll: (numbers: Int*)Unit
scala> printAll()
This case reveals some of the inner workings of how Scala handles varargs fields. By defining a varargs method that can take multiple integers, and then calling that method (a) with arguments, and (b) without arguments, you can see how Scala handles the two situations:
def printAll(numbers: Int*) {
println(numbers.getClass)
}
scala> printAll(1, 2, 3)
class scala.collection.mutable.WrappedArray$ofInt
scala> printAll()
class scala.collection.immutable.Nil$
While the first situation reveals how Scala handles the normal “one or more arguments” situation, treating the “no args” situation as a Nil$ in the second situation keeps your code from throwing a NullPointerException.
Although the resulting types are different, as a practical matter, this isn’t too important. You’ll typically use a loop inside a method to handle a varargs field, and either of the following examples work fine whether the method is called with zero or multiple parameters:
// version 1
def printAll(numbers: Int*) {
numbers.foreach(println)
}
// version 2
def printAll(numbers: Int*) {
for (i <- numbers) println
}
| this post is sponsored by my books: | |||
#1 New Release |
FP Best Seller |
Learn Scala 3 |
Learn FP Fast |