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

Pattern Matching

Pattern matching with case classes is a powerful feature in Scala that allows for concise and expressive handling of different data structures. Case classes are regular classes which are immutable by default and decomposable through pattern matching. They are especially useful in functional programming paradigms for matching complex data types. Here's a basic overview of how you can use pattern matching with case classes:

  1. Define Case Classes: These are special classes in Scala defined using the case class keyword. They automatically provide implementations of toString, equals, and hashCode methods, making them useful for pattern matching.

  2. Pattern Matching Syntax: You use the match keyword followed by cases. Each case can destructure an instance of a case class, extracting its parts for further processing.

Example

Let's define a simple example to demonstrate pattern matching with case classes. Suppose we are dealing with a system that models basic geometric shapes:

sealed trait Shape
case class Circle(radius: Double) extends Shape
case class Rectangle(width: Double, height: Double) extends Shape
case class Square(side: Double) extends Shape

Here, Shape is a sealed trait, which means all implementations of Shape must be in the same file. This is useful for pattern matching because the compiler can warn about missing cases.

Next, let's define a function that uses pattern matching to compute the area of a shape:

def area(shape: Shape): Double = shape match 
  case Circle(radius) => Math.PI * radius * radius
  case Rectangle(width, height) => width * height
  case Square(side) => side * side

In this function, shape is matched against each case class (Circle, Rectangle, Square), and the appropriate formula is used to calculate the area based on the shape type.

Benefits of Using Case Classes with Pattern Matching

  • Readability: The intent of the code is clear and concise.
  • Safety: The compiler checks for exhaustiveness in match cases, ensuring that all possible cases are handled.
  • Decomposition: Pattern matching allows for easy decomposition of complex data types, making it straightforward to access and manipulate their components.