diff --git a/_overviews/scala3-book/control-structures.md b/_overviews/scala3-book/control-structures.md index 6598cb604..b982cf654 100644 --- a/_overviews/scala3-book/control-structures.md +++ b/_overviews/scala3-book/control-structures.md @@ -810,6 +810,53 @@ speak(Person("Bam Bam")) // "Bam Bam says, Bam bam!" {% endtab %} {% endtabs %} +#### Binding matched patterns to variables + +You can bind the matched pattern to a variable to use type-specific behavior. + +{% tabs pattern-binding class=tabs-scala-version %} +{% tab 'Scala 2' for=pattern-binding %} +```scala +trait Animal { + val name: String +} +case class Cat(name: String) extends Animal { + def meow: String = "Meow" +} +case class Dog(name: String) extends Animal { + def bark: String = "Bark" +} + +def speak(animal: Animal) = animal match { + case c @ Cat(name) if name == "Felix" => println(s"$name says, ${c.meow}!") + case d @ Dog(name) if name == "Rex" => println(s"$name says, ${d.bark}!") + case _ => println("I don't know you!") +} + +speak(Cat("Felix")) // "Felix says, Meow!" +speak(Dog("Rex")) // "Rex says, Bark!" +``` +{% endtab %} +{% tab 'Scala 3' for=pattern-binding %} +```scala +trait Animal: + val name: String +case class Cat(name: String) extends Animal: + def meow: String = "Meow" +case class Dog(name: String) extends Animal: + def bark: String = "Bark" + +def speak(animal: Animal) = animal match + case c @ Cat(name) if name == "Felix" => println(s"$name says, ${c.meow}!") + case d @ Dog(name) if name == "Rex" => println(s"$name says, ${d.bark}!") + case _ => println("I don't know you!") + +speak(Cat("Felix")) // "Felix says, Meow!" +speak(Dog("Rex")) // "Rex says, Bark!" +``` +{% endtab %} +{% endtabs %} + ### Using a `match` expression as the body of a method Because `match` expressions return a value, they can be used as the body of a method. diff --git a/_tour/pattern-matching.md b/_tour/pattern-matching.md index 1038e6be1..a89c16775 100644 --- a/_tour/pattern-matching.md +++ b/_tour/pattern-matching.md @@ -236,6 +236,27 @@ def goIdle(device: Device): String = device match `def goIdle` has a different behavior depending on the type of `Device`. This is useful when the case needs to call a method on the pattern. It is a convention to use the first letter of the type as the case identifier (`p` and `c` in this case). +## Binding matched patterns to variables +You can use variable binding to get type-dependent behavior while simultaneously extracting fields from the matched pattern. + +{% tabs pattern-matching-variable-binding class=tabs-scala-version %} +{% tab 'Scala 2' for=pattern-matching-variable-binding %} +```scala mdoc +def goIdleWithModel(device: Device): String = device match { + case p @ Phone(model) => s"$model: ${p.screenOff}" + case c @ Computer(model) => s"$model: ${c.screenSaverOn}" +} +``` +{% endtab %} +{% tab 'Scala 3' for=pattern-matching-variable-binding %} +```scala +def goIdleWithModel(device: Device): String = device match + case p @ Phone(model) => s"$model: ${p.screenOff}" + case c @ Computer(model) => s"$model: ${c.screenSaverOn}" +``` +{% endtab %} +{% endtabs %} + ## Sealed types You may have noticed that in the examples above the base types are qualified