Scala: How to add ‘if’ expressions (guards) to match/case expressions

This is an excerpt from the 1st Edition of the Scala Cookbook (partially modified for the internet). This is Recipe 3.13, “How to add if expressions (guards) to Scala match/case expressions.”

Problem

You want to add qualifying logic to a case statement in a Scala match expression, such as allowing a range of numbers, or matching a pattern, but only if that pattern matches some additional criteria.

Solution

Add an if guard to your case statement. Use it to match a range of numbers:

i match {
    case a if 0 to 9 contains a => println("0-9 range: " + a)
    case b if 10 to 19 contains b => println("10-19 range: " + b)
    case c if 20 to 29 contains c => println("20-29 range: " + c)
    case _ => println("Hmmm...")
}

Use it to match different values of an object:

num match {
    case x if x == 1 => println("one, a lonely number")
    case x if (x == 2 || x == 3) => println(x)
    case _ => println("some other value")
}

You can reference class fields in your if guards. Imagine here that x is an instance of a Stock class that has symbol and price fields:

stock match {
    case x if (x.symbol == "XYZ" && x.price < 20) => buy(x)
    case x if (x.symbol == "XYZ" && x.price > 50) => sell(x)
    case _ => // do nothing
}

You can also extract fields from case classes and use those in your guards:

def speak(p: Person) = p match {
    case Person(name) if name == "Fred" => println("Yubba dubba doo")
    case Person(name) if name == "Bam Bam" => println("Bam bam!")
    case _ => println("Watch the Flintstones!")
}

Discussion

You can use this Scala syntax whenever you want to add simple matches to your case statements on the left side of the expression.

Note that all of these examples could be written by putting the if tests on the right side of the expressions, like this:

case Person(name) =>
    if (name == "Fred") println("Yubba dubba doo")
    else if (name == "Bam Bam") println("Bam bam!")

However, for many situations, your code will be simpler and easier to read by joining the if guard directly with the case statement.

I hope it has been helpful. All the best, Al.