Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Advanced Pattern Matching

Advanced pattern matching in Scala extends beyond simple case class decomposition, offering powerful features that allow for more intricate and nuanced control flow based on the shape and characteristics of data. These features include nested patterns, pattern guards, type patterns, extractor objects, and more. Let's explore some of these advanced concepts:

1. Nested Patterns

Pattern matching can be nested to decompose complex data structures. This is particularly useful when working with nested case classes or tuples.

case class Person(name: String, address: Address)
case class Address(city: String, country: String)

def matchPerson(person: Person): String = person match {
  case Person(_, Address("New York", "USA")) => "Lives in New York, USA"
  case Person(name, Address(city, _)) => s"$name lives in $city"
}

2. Pattern Guards

Pattern guards provide additional filtering conditions for a match case, using an if clause. This can refine the selection criteria for a particular pattern.

def evaluateNumber(number: Int): String = number match {
  case x if x > 0 => "Positive number"
  case x if x == 0 => "Zero"
  case x if x < 0 => "Negative number"
}

3. Type Patterns

Type patterns allow you to match objects based on their type. This can be particularly useful for polymorphic behavior in pattern matching.

def printType(x: Any): String = x match {
  case _: Int => "This is an integer"
  case _: String => "This is a string"
  case _ => "Unknown type"
}

4. Extractor Objects

Extractor objects allow for custom pattern matching logic by defining an unapply method. This method enables an object to be deconstructed in a custom way for pattern matching.

object Even {
  def unapply(arg: Int): Option[Int] = if (arg % 2 == 0) Some(arg) else None
}

def checkEven(number: Int): String = number match {
  case Even(n) => s"$n is even"
  case _ => s"$n is odd"
}

5. Matching on Collections

Scala allows pattern matching on collections such as Lists, Arrays, and more, with patterns that can match specific collection characteristics.

def listMatcher(list: List[Int]): String = list match {
  case List(_, _, third) => s"The third element is $third"
  case head :: tail => s"The head is $head"
  case Nil => "The list is empty"
}

6. Case Class Sequence Patterns

You can match sequences of case classes, combining the power of case classes with collection pattern matching.

def processShapes(shapes: List[Shape]): String = shapes match {
  case Circle(_) :: Rectangle(_, _) :: Nil => "A circle followed by a rectangle"
  case _ => "Other shapes sequence"
}

These advanced features greatly enhance the expressiveness and flexibility of pattern matching in Scala, enabling concise and powerful data manipulation and control flow mechanisms.

Exercises