Scala Guards in Pattern Matching and Case Statements


Guards are constructs that we can use to increase the power of pattern matching. Using guards, we can perform simple tests and comparisons on the variables in a pattern.

The general syntax of the guard statement is as follows:

pattern guard => result

Where,

  • pattern: The pattern to match.
  • guard: A boolean expression that must evaluate to true for the pattern to match.
  • result: The expression to evaluate if the pattern matches and the guard condition is satisfied.

The if statement must be used when a guard condition is specified.

Try this example of how guards can be used -

Example

object Demo {
  def main(args: Array[String]): Unit = {
    println(matchTest(11))
    println(matchTest(5))
    println(matchTest("Scala"))
  }
  
  def matchTest(x: Any): String = x match {
    case i: Int if i > 10 => "greater than 10"
    case i: Int if i < 10 => "less than 10"
    case _ => "not an integer"
  }
}

Save the above program in Demo.scala. Use the following commands to compile and execute this program.

Command

> scalac Demo.scala
> scala Demo

Output

greater than 10
less than 10
not an integer

The following points need to be noted about the above example -

  • The matchTest function is defined with guards. The first case has a guard condition to check if the integer is greater than 10. If true, it returns "greater than 10".
  • The second case checks if the integer is less than 10. If true, it returns "less than 10".
  • The third case catches all other values and returns "not an integer".

Guards for if Statements

Guards can also be used for if statements so that the series of statements executed is based on the guard condition. Try this following example to see how we can achieve this -

Example

object Demo {
  def main(args: Array[String]): Unit = {
    val N = 9
    if (N > 10) {
      println("N is greater than 10")
    } else {
      println("N is less than 10")
    }
  }
}

The following points need to be noted about the above example -

  • The guard condition is used within the if If the guard condition evaluates to true, the statement "N is greater than 10" is displayed.
  • If the guard condition evaluates to false, the statement "N is less than 10" is displayed.

Save the above program in Demo.scala. Use the following commands to compile and execute this program.

Command

> scalac Demo.scala
> scala Demo

Output

N is less than 10

Guards for case Statements

Guards can also be used for case statements so that the series of statements executed is based on the guard condition. Try this following example to see how we can achieve this -

Example

object Demo {
  def main(args: Array[String]): Unit = {
    val A = 9
    A match {
      case x if x > 10 => println("The value of A is greater than 10")
      case _ => println("The value of A is less than 10")
    }
  }
}

The following points need to be noted about the above example -

  • The guard condition is used along with the case If the guard condition evaluates to true, the statement "The value of A is greater than 10" is displayed.
  • If the guard condition evaluates to anything else, the statement "The value of A is less than 10" is displayed.

Command

> scalac Demo.scala
> scala Demo

Output

The value of A is less than 10

Multiple Guard Conditions

Multiple guard conditions can also be specified for a pattern. The general syntax of the guard statement with multiple guard conditions is as follows:

case pattern if condition1 && condition2 && ... => result

Where,

  • pattern: The pattern to match.
  • condition1, condition2, ...: These are the multiple guard conditions which are applied to the pattern.
  • result: The expression to evaluate if the pattern matches and all guard conditions are satisfied.

Try this following example of how multiple guards can be used -

Example

object Demo {
  def main(args: Array[String]): Unit = {
    println(matchTest(11))
    println(matchTest(5))
    println(matchTest("Scala"))
  }
  
  def matchTest(x: Any): String = x match {
    case i: Int if i > 10 && i % 2 == 0 => "greater than 10 and even"
    case i: Int if i > 10 && i % 2 != 0 => "greater than 10 and odd"
    case i: Int if i < 10 => "less than 10"
    case _ => "not an integer"
  }
}

Save the above program in Demo.scala. Use the following commands to compile and execute this program.

Command

> scalac Demo.scala
> scala Demo

Output

greater than 10 and odd
less than 10
not an integer

The following points need to be noted about the above example -

  • The first case checks if the integer is greater than 10 and even. If true, it returns "greater than 10 and even".
  • The second case checks if the integer is greater than 10 and odd. If true, it returns "greater than 10 and odd".
  • The third case checks if the integer is less than 10. If true, it returns "less than 10".
  • The fourth case catches all other values and returns "not an integer".

Guards in Case Classes

Case classes can also benefit from using guards in pattern matching to add additional conditions.

Example

case class Person(name: String, age: Int)

object Demo {
  def main(args: Array[String]): Unit = {
    val alice = Person("Alice", 25)
    val bob = Person("Bob", 32)
    val charlie = Person("Charlie", 32)
  
    for (person <- List(alice, bob, charlie)) {
      person match {
        case Person(name, age) if age < 30 => println(s"Hi $name, you are young!")
        case Person(name, age) if age >= 30 => println(s"Hi $name, you are experienced!")
      }
    }
  }
}

Save the above program in Demo.scala. Use the following commands to compile and execute this program.

Command

> scalac Demo.scala
> scala Demo

Output

Hi Alice, you are young!
Hi Bob, you are experienced!
Hi Charlie, you are experienced!

The following points need to be noted about the above example -

  • The first case checks if the age of person is less than 30. If true, it returns a message indicating youth.
  • The second case checks if the age of person is 30 or greater. If true, it returns a message indicating experience.

Scala Guards Summary

  • Guards are powerful constructs in Scala that enhance pattern matching by adding conditions to patterns.
  • Guards can be used with if, case, and pattern matching
  • You can specify multiple guard conditions to create more complex and precise pattern matches.
  • Guards can be used in case classes, providing flexibility in pattern matching.
  • Guards can be used in list and tuple matching to apply conditions based on the elements of these collections.