Learn How To Use Pattern Matching
Overview
In this tutorial, we will show a functional feature of Scala which is pattern matching.
If you have used Java or .NET in the past, pattern matching may at first sight appear similar to switch statements. But, Scala's pattern matching is a lot more powerful!
Steps
1. Pattern matching 101 - a very basic example
Suppose you want to test a variable called donutType. In the case that its value is Glazed Donut, you will print Very Tasty. On the other hand, if its value is Plain Donut, then you will print Tasty.
println("Step 1: Pattern matching 101 - a very basic example")
val donutType = "Glazed Donut"
donutType match {
case "Glazed Donut" => println("Very tasty")
case "Plain Donut" => println("Tasty")
}
You should see the following output when you run your Scala application in IntelliJ:
Step 1: Pattern matching 101 - a very basic example
Very tasty
NOTE:
- You should have noticed that unlike in Java or in .NET, there are no break statements!
- I'm pretty sure that you must have seen your share of bugs which come from the fact that someone forgot to use the break clause. In Java or .NET, this would allow the logic to fall-through to the next case statement.
- Another big thanks to Scala as the compiler is smart enough to prevent fall-through and hence there is no need to use a break clause with pattern matching.
2. Pattern matching and return the result
What if instead of simply printing the different taste level of a donut, you would like to store it in a variable. Similar to what you've learned in If And Else Expression and For Comprehension, Scala's pattern matching can return the result back to the caller.
println("\nStep 2: Pattern matching and return the result")
val tasteLevel = donutType match {
case "Glazed Donut" => "Very tasty"
case "Plain Donut" => "Tasty"
}
println(s"Taste level of $donutType = $tasteLevel")
You should see the following output when you run your Scala application in IntelliJ:
Step 2: Pattern matching and return the result
Taste level of Glazed Donut = Very tasty
NOTE:
- Notice that you did not have to use the return keyword as you would in say Java or .NET.
- Instead, the last expression will be the one returned back to the caller. We will see more return types as we get to tutorials on functions.
3. Pattern matching using the wildcard operator
As you have learned in Step 1, there is no need to use any break clauses as there is no fall-through when using pattern matching. But, what if you needed to provide a default case?
println("\nStep 3: Pattern matching using the wildcard operator")
val tasteLevel2 = donutType match {
case "Glazed Donut" => "Very tasty"
case "Plain Donut" => "Tasty"
case _ => "Tasty"
}
println(s"Taste level of $donutType = $tasteLevel2")
You should see the following output when you run your Scala application in IntelliJ:
Step 3: Pattern matching using the wildcard operator
Taste level of Glazed Donut = Very tasty
NOTE:
- If you come from a pure Object Oriented programming background, using the wildcard operator will almost certainly feel unnatural.
- Don't worry, we will see more examples of the wildcard operator in upcoming tutorials!
4. Pattern matching with two or more items on the same condition
In our example, we are labelling Glazed Donut item as Very Tasty. What if a Strawberry Donut was also Very Tasty. This behavior seems similar to an OR expression and you can use the pipe |
println("\nStep 4: Pattern matching with two or more items on the same condition")
val tasteLevel3 = donutType match {
case "Glazed Donut" | "Strawberry Donut" => "Very tasty"
case "Plain Donut" => "Tasty"
case _ => "Tasty"
}
println(s"Taste level of $donutType = $tasteLevel3")
You should see the following output when you run your Scala application in IntelliJ:
Step 4: Pattern matching with two or more items on the same condition
Taste level of Glazed Donut = Very tasty
5. Pattern matching and using if expressions in the case clause
Similar to Step 4, you can simulate an OR clause by adding If Expression in the case statements.
println("\nStep 5; Pattern matching and using if expressions in the case clause")
val tasteLevel4 = donutType match {
case donut if (donut.contains("Glazed") || donut.contains("Strawberry")) => "Very tasty"
case "Plain Donut" => "Tasty"
case _ => "Tasty"
}
println(s"Taste level of $donutType = $tasteLevel4")
You should see the following output when you run your Scala application in IntelliJ:
Step 5; Pattern matching and using if expressions in the case clause
Taste level of Glazed Donut = Very tasty
6. Pattern matching by types
So far we have been pattern matching on the value of some variable. What if you would like to pattern match on the type of the variable?
Let's declare a variable explicitly to be of type Any to hold the price of one donut. As you have learned in the Type Inference tutorial, the Scala compiler would infer that priceOfDonut to be of type Double.
Let's use pattern matching to prove it!
println("\nStep 6: Pattern matching by types")
val priceOfDonut: Any = 2.50
val priceType = priceOfDonut match {
case price: Int => "Int"
case price: Double => "Double"
case price: Float => "Float"
case price: String => "String"
case price: Boolean => "Boolean"
case price: Char => "Char"
case price: Long => "Long"
}
println(s"Donut price type = $priceType")
You should see the following output when you run your Scala application in IntelliJ:
Step 6: Pattern matching by types
Donut price type = Double
NOTE:
- If you come from Java or .NET, you can think of the Any type similar to the Object class.
- In other words, Any is at the root of Scala's type hierarchy as shown per the Scala Documentation.
Summary
In this tutorial, we went over the following:
- How to use basic pattern matching
- How to use pattern matching and return the result back to the caller
- How to use pattern matching with the wildcard operator
- How to use pattern matching with two or more items on the same condition
- How to use pattern matching with if expressions in the case clause
- How to use pattern matching on types
Tip
- This tutorial only shows some of the features of pattern matching. We will see other usage of pattern matching in upcoming tutorials.
Source Code
The source code is available on the allaboutscala GitHub repository.
What's Next
In the next tutorial, I will go over Tuples in Scala.
Stay tuned!