scalaadvanced

Advanced Pattern Matching Techniques

Master advanced patterns: custom extractors, unapply, variable binding, and deep matching.

scala
// Custom extractor (unapply)
object Even:
  def unapply(n: Int): Option[Int] =
    if n % 2 == 0 then Some(n / 2) else None

object Positive:
  def unapply(n: Int): Boolean = n > 0

// Extractor with multiple values
object Email:
  def unapply(s: String): Option[(String, String)] =
    s.split("@") match
      case Array(local, domain) => Some((local, domain))
      case _ => None

// Sequence extractor (unapplySeq)
object Words:
  def unapplySeq(s: String): Option[Seq[String]] =
    Some(s.trim.split("\\s+").toSeq).filter(_.nonEmpty)

// Regex extractors
val DatePattern = """(\d{4})-(\d{2})-(\d{2})""".r
val IpPattern = """(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})""".r

// Deep matching with @ binding
case class Address(street: String, city: String, country: String)
case class Person(name: String, age: Int, address: Address)

def describe(p: Person): String = p match
  case Person(name, age, _) if age < 18 =>
    s"$name is a minor"
  case Person(name, _, addr @ Address(_, _, "US")) =>
    s"$name lives in the US at ${addr.city}"
  case Person(name, age, Address(_, city, country)) =>
    s"$name ($age) from $city, $country"

// Type test patterns
def process(x: Any): String = x match
  case list: List[?] if list.nonEmpty =>
    s"Non-empty list with ${list.size} elements"
  case map: Map[?, ?] =>
    s"Map with ${map.size} entries"
  case s: String if s.length > 10 =>
    s"Long string: ${s.take(10)}..."
  case _ => x.toString

@main def run(): Unit =
  // Custom extractors
  42 match
    case Even(half) => println(s"42 is even, half = $half")

  7 match
    case Even(half) => println(s"7 is even, half = $half")
    case _          => println("7 is odd")

  // Boolean extractor
  val nums = List(-3, -1, 0, 2, 5, -4)
  val positives = nums.collect { case n @ Positive() => n }
  println(s"Positives: $positives")

  // Email extractor
  "alice@example.com" match
    case Email(local, domain) =>
      println(s"Local: $local, Domain: $domain")

  // Sequence extractor
  "Hello World Scala" match
    case Words(first, second, _*) =>
      println(s"First two words: $first, $second")

  // Regex extractors
  "2024-01-15" match
    case DatePattern(y, m, d) =>
      println(s"Year: $y, Month: $m, Day: $d")

  "192.168.1.1" match
    case IpPattern(a, b, c, d) =>
      println(s"IP: $a.$b.$c.$d")

  // Deep matching
  val alice = Person("Alice", 30, Address("123 Main", "NYC", "US"))
  val bob = Person("Bob", 15, Address("456 High", "London", "UK"))
  println(describe(alice))
  println(describe(bob))

  // Pattern matching in val
  val (x, y, z) = (1, 2, 3)
  val head :: tail = List(1, 2, 3, 4): @unchecked
  println(s"Head: $head, Tail: $tail")

Use Cases

  • Custom domain extractors
  • Deep nested data matching
  • Input parsing with regex patterns

Tags

Related Snippets

Similar patterns you can reuse in the same workflow.