In Scala I am trying to understand pattern matching ,however most of the patterns are self explanatory but constructor pattern and variable binding pattern looks confusing to me . I tried following example from Programming Scala ,2ed
case class Address(street: String, city: String, country: String)
case class Person(name: String, age: Int, address: Address)
object ScalaCaseDemoMain extends App{
val alice = Person("Alice", 25, Address("1 Scala Lane", "Chicago", "USA"))
val bob = Person("Bob", 29, Address("2 Java Ave.", "Miami", "USA"))
val charlie = Person("Charlie", 32, Address("3 Python Ct.", "Boston", "USA"))
for (person <- Seq(alice, bob, charlie)) {
person match {
case p @ Person("Alice", 25, address) => println(s"Hi Alice! $p")
case p @ Person("Bob", 29, a @ Address(street, city, country)) =>
println(s"Hi ${p.name}! age ${p.age}, in ${a.city}")
case p @ Person(name, age, _) =>
println(s"Who are you, $age year-old person named $name? $p")
}
}
}
I want to know when to use constructor pattern
case Person("Alice", 25, address) => //some action here
and when to use variable binding pattern
case p @ Person("Alice", 25, address) //some action here
I am always confused while It comes to pattern matching ?
The pattern you call constructor is in most cases called an Extractor
or Deconstructor
.
It is like a reversed constructor as you can see by the method it calls unapply
.
If it would occur on the right hand side or outside the pattern match
it would be as you noted a Constructor
.
@
only is used in pattern matching
to bind the deconstructed entity to a variable.
It's purpose is to supplies the option to catch the whole expression and still be able to use extracted values in later steps.
So there would always be a way to arrange the code in a way that you would not need to use @
but it could help readability a lot.
An usage example for @
is:
You want to send a mail to all Persons named "Alice" which are older than "21" but the address is no important selection criterium.
case p @ Person("Alice", age, _) if age > 21 => storePersonForMailing(p)
Here the pattern match shows clearly your intention by stressing the values you use for the selection and as you need the address later for sending the mail it would be no good idea to drop it.