Matching Multiple Conditions with One Case Statement
Problem
You have a situation where several match conditions require that the same business logic be executed, and rather than repeating your business logic for each case, you’d like to use one copy of the business logic for the matching conditions.
Solution
Place the match conditions that invoke the same business logic on one line, separated by the | (pipe) character:
val i = 5
i match {
case 1 | 3 | 5 | 7 | 9 => println("odd")
case 2 | 4 | 6 | 8 | 10 => println("even")
}
This same syntax works with strings and other types. Here’s an example based on a String match:
val cmd = "stop"
cmd match {
case "start" | "go" => println("starting")
case "stop" | "quit" | "exit" => println("stopping")
Assigning the Result of a Match Expression to a Variable
Problem
You want to return a value from a match expression and assign it to a variable, or use a match expression as the body of a method.
Solution
To assign a variable to the result of a match expression, insert the variable assignment before the expression, as with the variable evenOrOdd in this example:
val evenOrOdd = someNumber match {
case 1 | 3 | 5 | 7 | 9 => println("odd")
case 2 | 4 | 6 | 8 | 10 => println("even")
}
This approach is commonly used to create short methods or functions. For example, the following method implements the Perl definitions of true and false:
Accessing the Value of the Default Case in a Match Expression
Problem
You want to access the value of the default, “catch all” case when using a match expression, but you can’t access the value when you match it with the _ wildcard syntax.
Solution
Instead of using the _ wildcard character, assign a variable name to the default case:
i match {
case 0 => println("1")
case 1 => println("2")
case default => println("You gave me: " + default)
You need to match one or more patterns in a match expression, and the pattern may be a constant pattern, variable pattern, constructor pattern, sequence pattern, tuple pattern, or type pattern.
Solution
Define a case statement for each pattern you want to match. The following method shows examples of many different types of patterns you can use in match expressions:
def echoWhatYouGaveMe(x: Any): String = x match {
// constant patterns
case 0 => "zero"
case true => "true"
case "hello" => "you said 'hello'"
case Nil => "an empty List"
// sequence patterns
case List(0, _, _) => "a three-element list with 0 as the first element"
case List(1, _*) => "a list beginning with 1, having any number of elements"
case Vector(1, _*) => "a vector starting with 1, having any number of elements"
// tuples
case (a, b) => s"got $a and $b"
case (a, b, c) => s"got $a, $b, and $c"
// constructor patterns
case Person(first, "Alexander") => s"found an Alexander, first name = $first"
case Dog("Suka") => "found a dog named Suka"
// typed patterns
case s: String => s"you gave me this string: $s"
case i: Int => s"thanks for the int: $i"
case f: Float => s"thanks for the float: $f"
case a: Array[Int] => s"an array of int: ${a.mkString(",")}"
case as: Array[String] => s"an array of strings: ${as.mkString(",")}"
case d: Dog => s"dog: ${d.name}"
case list: List[_] => s"thanks for the List: $list"
You want to match different case classes (or case objects) in a match expression, such as when receiving messages in an actor.
Solution
Use the different patterns shown in the previous recipe to match case classes and objects, depending on your needs.
The following example demonstrates how to use patterns to match case classes and case objects in different ways, depending primarily on what information you need on the right side of each case statement. In this example, the Dog and Cat case classes and the Woodpecker case object are different subtypes of the Animal trait:
trait Animal
case class Dog(name: String) extends Animal
case class Cat(name: String) extends Animal
case object Woodpecker extends Animal
object CaseClassTest extends App {
def determineType(x: Animal): String = x match {
case Dog(moniker) => "Got a Dog, name = " + moniker
Because the methods in the body of the class are part of the constructor, when an instance of a Person class is created, you’ll see the output from the println statements at the beginning and end of the class declaration, along with the call to the printHome and printFullName methods near the bottom of the class:
4.2. Controlling the Visibility of Constructor Fields
Problem
You want to control the visibility of fields that are used as constructor parameters in a Scala class.
Solution
As shown in the following examples, the visibility of constructor fields in a Scala class is controlled by whether the fields are declared as val, var, without either val or var, and whether private is also added to the fields.
Here’s the short version of the solution:
If a field is declared as a var, Scala generates both getter and setter methods for that field.
If the field is a val, Scala generates only a getter method for it.
If a field doesn’t have a var or val modifier, Scala gets conservative, and doesn’t generate a getter or setter method for the field.
Additionally, var and val fields can be modified with the private keyword, which prevents getters and setters from being generated.
You want to define one or more auxiliary constructors for a class to give consumers of the class different ways to create object instances.
Solution
Define the auxiliary constructors as methods in the class with the name this. You can define multiple auxiliary constructors, but they must have different signatures (parameter lists). Also, each constructor must call one of the previously defined constructors.
The following example demonstrates a primary constructor and three auxiliary constructors:
// primary constructor
class Pizza (var crustSize: Int, var crustType: String) {