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
xargs
on 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 |