Pattern matching is Scala's main way to branch on the shape of data.
A match expression tests a value against patterns in order and evaluates the first matching case: x match { case pattern => result ... }. It's an expression, so it returns a value.
Pattern kinds:
- Literals:
case 0 =>,case "quit" =>. - Variables and the wildcard:
case n =>binds anything ton;case _ =>matches anything without binding. - Types:
case s: String =>matches and casts in one step. - Constructors of case classes, nested freely:
case Order(id, Customer(name, _)) =>. - Tuples and sequences:
case (a, b) =>,case List(first, rest*) =>,case head :: tail =>. - Alternatives
case 1 | 2 =>and binderscase p @ Point(0, _) =>.
A guard adds a condition: case n if n < 0 =>. If no case matches, a MatchError is thrown at runtime, which is why matching on a sealed hierarchy or enum is preferred: the compiler then warns when a case is missing.
Variable patterns start with a lowercase letter. To compare against an existing value instead of binding a new name, use backticks (` case expected => `) or an uppercase constant.
Patterns also work in val definitions (val (q, r) = (7 / 2, 7 % 2)), in for generators and in lambdas passed to collect.
Example
case class Customer(name: String, vip: Boolean)
case class Order(id: Int, customer: Customer, total: Double)
def describe(x: Any): String = x match
case 0 => "zero"
case n: Int if n < 0 => s"negative int $n"
case n: Int => s"int $n"
case s: String => s"string of length ${s.length}"
case (a, b) => s"pair $a and $b"
case List(first, rest*) => s"list starting $first, ${rest.size} more"
case Order(id, Customer(name, true), _) => s"VIP order $id for $name"
case _ => "something else"
println(describe(-4)) // negative int -4
println(describe("hey")) // string of length 3
println(describe((1, "a"))) // pair 1 and a
println(describe(List(9, 8, 7))) // list starting 9, 2 more
println(describe(Order(7, Customer("Ana", true), 99.0))) // VIP order 7 for Ana
println(describe(3.5)) // something else
val (q, r) = (17 / 5, 17 % 5)
println(s"$q remainder $r") // 3 remainder 2Remember
- Cases are tried top to bottom; the first match wins
- Patterns destructure case classes, tuples and sequences, with guards
- Lowercase names bind; use backticks to compare to an existing value
- Unmatched values throw MatchError
Watch out for
- Writing
case expected =>meaning the variableexpected: it creates a new binding that matches everything.