Scala Pattern Matching
Scala provides a powerful pattern matching mechanism, and it is also widely used.
A pattern match contains a series of alternatives, each starting with the keywordcase. Each alternative contains a pattern and one or more expressions. The arrow symbol=>separates the pattern and expressions.
Below is a simple integer value pattern matching example:
Example
def main(args: Array[String]) {
println(matchTest(3))
}
def matchTest(x: Int): String = x match {
case 1 => "one"
case 2 => "two"
case _ => "many"
}
}
Executing the above code produces the following output:
$ scalac Test.scala $ scala Test many
match corresponds to switch in Java, but is written after the selector expression. That is:selector match { alternatives }.
The match expression is evaluated by trying each pattern in the order written in the code. As soon as a matching case is found, the remaining cases will not continue to be matched.
Next, let's look at a pattern matching example for different data types:
Example
def main(args: Array[String]) {
println(matchTest("two"))
println(matchTest("test"))
println(matchTest(1))
println(matchTest(6))
}
def matchTest(x: Any): Any = x match {
case 1 => "one"
case "two" => 2
case y: Int => "scala.Int"
case _ => "many"
}
}
Executing the above code produces the following output:
$ scalac Test.scala $ scala Test 2 many one scala.Int
In the example, the first case corresponds to the integer value 1, the second case corresponds to the string value two, and the third case corresponds to a type pattern, used to determine whether the passed value is an integer. Compared to using isInstanceOf to determine the type, using pattern matching is better. The fourth case represents the default full-match alternative, that is, the match item when no other match is found, similar to default in switch.
Using Case Classes
A class definition that uses the case keyword is a case class. Case classes are a special kind of class, optimized for pattern matching.
The following is a simple example of a case class:
Example
def main(args: Array[String]) {
val alice = new Person("Alice", 25)
val bob = new Person("Bob", 32)
val charlie = new Person("Charlie", 32)
for (person <- List(alice, bob, charlie)) {
person match {
case Person("Alice", 25) => println("Hi Alice!")
case Person("Bob", 32) => println("Hi Bob!")
case Person(name, age) =>
println("Age: " + age + " year, name: " + name + "?")
}
}
}
// Case class
case class Person(name: String, age: Int)
}
Executing the above code produces the following output:
$ scalac Test.scala $ scala Test Hi Alice! Hi Bob! Age: 32 year, name: Charlie?
When a case class is declared, the following happens automatically:
- Each parameter of the constructor becomes a val, unless it is explicitly declared as var, but this is not recommended;
- An apply method is provided in the companion object, so objects can be constructed without using the new keyword;
- An unapply method is provided to make pattern matching work;
- toString, equals, hashCode and copy methods are generated, unless these methods are explicitly defined.