Match
In languages like Scala 3.3 we often need to handle special cases based on the values in our data. Pattern matching is a solution—and Scala supports pattern matching.
With the match keyword, we begin a match construct. We use cases to indicate values to be matched. We can return values directly from cases.
Here we implement a function called colorCode
. It accepts an id Int
and returns a String
. A match construct determines which string
to return based on the Int
.
case
-keyword to specify cases to return. Here we use simple cases for single Ints, but more complex forms may be used.// Use match on parameter id and return a String. // ... Default case returns "None" String. def colorCode(id: Int): String = id match { case 0 => "Blue" case 1 => "Red" case 2 => "Green" case _ => "None" } object Program { def main(args: Array[String]): Unit = { // Get color code for this argument. val result = colorCode(0) println(result) val result2 = colorCode(1) println(result2) val result3 = colorCode(4000) println(result3) } }Blue Red None
List
pattern matchingTo use pattern matching, we provide special syntax forms. For example, to match lists we specify 3 identifiers separated by "::" tokens.
testList
function matches lists with 2 or more elements, and returns true if the second element is greater than the first.// Return true if list has two or more elements. // Second element must be greater than the first. // ... Return false for all other lists. def testList(x: List[Int]): Boolean = x match { case a :: b :: c => b > a case _ => false } object Program { def main(args: Array[String]): Unit = { // Call testList. val result1 = testList(List(10, 20, 30)) val result2 = testList(List(20, 10)) val result3 = testList(List()) val result4 = testList(List(1, 0, 2, 3)) val result5 = testList(List(0, 1, 2, 3)) println(result1) println(result2) println(result3) println(result4) println(result5) } }true false false false true
An option can be evaluated in match statement. An option is either Some value or is None
. We can use Some and None
in a match construct.
GetOption
returns an Option
that wraps an Int
. If we pass 1 or greater, we get Some value. Otherwise we get None
.getOption
which returns a valid option. The Some case in the match block is reached. A value exists.// Return Some or None option based on integer. def getOption(n: Int): Option[Int] = if (n >= 1) Some(n) else None object Program { def main(args: Array[String]): Unit = { // Get an option. val result = getOption(2) // Match option on Some and None. result match { case Some(x) => println("Value exists") case None => println("Nothing exists") } } }Value exists
We can capture variables in cases and use if
-statements to test those variables values. These are guarded, conditional cases.
string
. Its result is stored in the "result" value and then printed to the screen.object Program { def main(args: Array[String]): Unit = { val magnitude = 5 // Match on magnitude, returning a string. // ... Handle greater than or equal to 4. // Handle less than or equal to 1. val result = magnitude match { case m if m >= 4 => "Big, greater than or equal to 4" case m if m <= 1 => "Small, less than or equal to 1" case _ => "Medium" } // Print result. println(result) } }Big, greater than or equal to 4
List
pattern notesLet us research list pattern matching. We find that the pattern to match lists has three parts separated by "::" symbols.
The pattern x :: y :: xs matches lists of length >= 2, binding x to the list's first element, y to the list's second element, and xs to the remainder.
A tuple can be matched. The syntax is similar to a list pattern. We can require specific values in any part of the tuple being matched.
Pattern matching is similar to a "switch
" statement in C-like languages. But in Scala we can use more advanced patterns. This simplifies code and makes it clearer.