← Scala EnglishChapter 09 of 13

Pattern Matching

## Learning Objectives - Master match expressions - Learn pattern types - Use guards in patterns - Work with case objects - Understand extractors ## Basic match Expression ### Syntax ```scala val x = 10 val result = x match { case 1 => "one" case 2 => "two" case 3 => "three" case _ => "something else" } ``` ### match as Expression ```scala def describe(x: Any): String = x match { case 1 => "one" case "hello" => "a greeting" case true => "truth" case List(1, 2, 3) => "list of three numbers" case _ => "unknown" } ``` ## Pattern Types ### Constant Patterns ```scala def describe(x: Any): String = x match { case 0 => "zero" case true => "true" case "hello" => "greeting" case '\n' => "newline" case _ => "other" } ``` ### Variable Patterns ```scala def describe(x: Any): String = x match { case 0 => "zero" case something => s"value is $something" } ``` ### Wildcard Pattern ```scala x match { case 1 => "one" case _ => "not one" } ``` ### Type Patterns ```scala def describe(x: Any): String = x match { case i: Int => s"Integer: $i" case s: String => s"String: $s" case l: List[_] => s"List with ${l.length} elements" case _: BigInt => "big integer" case null => "null" case _ => "something else" } ``` ### List Patterns ```scala def describeList(lst: List[Int]): String = lst match { case List() => "empty list" case List(x) => s"single element: $x" case List(x, y) => s"two elements: $x and $y" case List(x, _*) => s"first element: $x, and more" case _ => "not a list" } // Cons patterns def sum(lst: List[Int]): Int = lst match { case head :: tail => head + sum(tail) case Nil => 0 } ``` ### Tuple Patterns ```scala def describeTuple(t: (Any, Any)): String = t match { case (x: Int, y: Int) => s"int pair: ($x, $y)" case (x: String, _) => s"string first: $x" case (_, _) => "any 2-tuple" } // Destructuring in patterns def add(tuple: (Int, Int, Int)) = tuple match { case (a, b, c) => a + b + c } ``` ### Case Class Patterns ```scala case class Person(name: String, age: Int) def describe(p: Person): String = p match { case Person("Alice", 30) => "Alice is 30" case Person(name, age) => s"$name is $age years old" } val alice = Person("Alice", 30) alice match { case Person(n, a) => println(s"$n, $a") } ``` ### Sealed Class Patterns ```scala sealed trait Result case class Success(data: Int) extends Result case class Failure(message: String) extends Result case object Pending extends Result def describe(result: Result): String = result match { case Success(n) => s"Success with $n" case Failure(msg) => s"Failed: $msg" case Pending => "Still pending" } ``` ## Guards ### Adding Conditions ```scala def describe(x: Int): String = x match { case i if i > 0 => "positive" case i if i < 0 => "negative" case 0 => "zero" } def grade(score: Int): Char = score match { case s if s >= 90 => 'A' case s if s >= 80 => 'B' case s if s >= 70 => 'C' case s if s >= 60 => 'D' case _ => 'F' } ``` ### Combining Patterns and Guards ```scala def describeList(lst: List[Int]): String = lst match { case List(1, _*) if lst.length >= 3 => "starts with 1, has 3+ elements" case List(x, y, z) if x + y == z => s"$x + $y = $z" case _ => "other" } ``` ## Case Objects ```scala sealed trait Status case object Ready extends Status case object Running extends Status case object Done extends Status case object Failed extends Status def describe(status: Status): String = status match { case Ready => "Ready to start" case Running => "Currently running" case Done => "Completed successfully" case Failed => "Failed" } ``` ## Extractors ### unapply Method ```scala class Person(val name: String, val age: Int) object Person { def apply(name: String, age: Int): Person = new Person(name, age) def unapply(p: Person): Option[(String, Int)] = Some((p.name, p.age)) } val p = Person("Alice", 30) p match { case Person(name, age) => s"$name is $age" } // Can also work with regular tuple val tuple = ("Bob", 25) tuple match { case (name, age) => s"$name is $age" } ``` ### Boolean Extractors ```scala object Even { def unapply(n: Int): Boolean = n % 2 == 0 } 42 match { case Even() => "even" case _ => "odd" } ``` ### Custom Extractors ```scala object Email { def unapply(str: String): Option[(String, String)] = { val parts = str.split("@") if (parts.length == 2) Some(parts(0), parts(1)) else None } } "user@example.com" match { case Email(user, domain) => s"User: $user, Domain: $domain" case _ => "Not an email" } ``` ## Pattern Matching in Assignments ```scala val (x, y) = (1, 2) val List(first, second, _*) = List(1, 2, 3, 4, 5) val Person(n, a) = Person("Alice", 30) ``` ## Pattern Matching in for Loops ```scala val people = List(("Alice", 30), ("Bob", 25), ("Charlie", 35)) for ((name, age) <- people if age >= 30) { println(s"$name is $age") } // With pattern matching people foreach { case (name, age) if age >= 30 => println(s"$name is $age") case (name, _) => println(s"$name is too young") } ``` ## Regex Patterns ```scala val emailRegex = "([a-z]+)@([a-z]+)\\.([a-z]+)".r "user@example.com" match { case emailRegex(user, domain, tld) => s"User: $user, Domain: $domain, TLD: $tld" case _ => "Invalid email" } // Extraction val emailRegex(user, domain, tld) = "user@example.com" // user = "user", domain = "example", tld = "com" ``` ## Partial Functions ```scala val divide: PartialFunction[(Int, Int), Int] = { case (a, b) if b != 0 => a / b } divide.isDefinedAt((10, 2)) // true divide.isDefinedAt((10, 0)) // false divide((10, 2)) // 5 ``` ## Exhaustive Patterns Scala compiler warns about non-exhaustive matches with sealed types: ```scala sealed trait Color case object Red extends Color case object Green extends Color case object Blue extends Color def describe(color: Color): String = color match { case Red => "red" case Green => "green" // Compiler warning: missing Blue } ``` ## Summary - `match` is Scala's powerful pattern matching expression - Patterns include constants, variables, types, lists, tuples, and case classes - Guards (`if`) add conditions to patterns - Case objects represent singleton values in sealed hierarchies - Extractors (`unapply`) enable custom pattern matching - Sealed types enable exhaustive matching - Partial functions handle subset-of-cases scenarios - Pattern matching works in assignments and for comprehensions

Comments

Comments powered by Giscus

To enable comments, add your Giscus embed code here.

Learn more about Giscus →