Scala by Example: Pattern Matching
Leveraging powerful pattern matching with this code example showing value matching, type matching, list destructuring with wildcards, case class deconstruction, guard conditions using if clauses, and default catch-all patterns for comprehensive control flow.
Code
def describe(x: Any): String = x match {
case 1 => "one"
case "hello" => "greeting"
case true => "truth"
case Nil => "empty list"
case List(0, _, _) => "list starting with 0, length 3"
case s: String => s"String: $s" // Type match
case _ => "something else" // Default case
}
println(describe(1))
println(describe(List(0, 5, 10)))
// Destructuring case classes
abstract class Notification
case class Email(sender: String, body: String) extends Notification
case class SMS(caller: String, msg: String) extends Notification
def showNotification(n: Notification): String = n match {
case Email(s, _) => s"Email from $s"
case SMS(c, m) if c == "12345" => s"SMS from boss: $m" // Guard
case SMS(c, _) => s"SMS from $c"
}Explanation
Pattern matching in Scala is significantly more powerful than traditional switch statements, allowing you to match against values, types, and even the structure of complex objects. The match keyword is followed by a series of case statements, each defining a pattern and the expression to evaluate if that pattern matches. Unlike Java's switch, Scala's match expressions are exhaustive and return values, making them true expressions rather than just control flow statements.
You can match against literal values, types using case x: Type, and collections with specific structures like case List(0, _, _) which matches a three-element list starting with zero. The wildcard _ acts as a placeholder for values you don't care about or as a catch-all default case. Type matching is particularly useful for handling polymorphic types safely, as the matched value is automatically cast to the matched type within that case block.
Pattern matching works seamlessly with case classes, allowing you to deconstruct them and extract their fields directly in the case statement. Guards can be added using if clauses to add conditional logic to a pattern, enabling very fine-grained control. For example, case SMS(c, m) if c == "12345" only matches SMS messages from a specific caller. This combination of structural matching, type checking, and conditional guards makes pattern matching an incredibly expressive tool for handling complex branching logic.
Code Breakdown
case List(0, _, _) matches 3-element list starting with 0; _ ignores values.s: String performs type match, binding value to s with String type.Email(s, _) deconstructs case class extracting sender, ignoring body.if c == "12345" is guard; case only matches when condition is true.
