Reputation: 21
I'm new to Scala but I was told that "You are checking if "Toronto Raptor" == matchNY." for the following code snippet @ https://issues.scala-lang.org/browse/SI-7210, and I really don't have any idea why "Totonto Raptor" is the only string chosen in the for loop to be matched with the regular expression, can someone explain this to me please ?
Thanks.
David
val matchNY = "^.*New.*$".r
val teams = List(
"Toronto Raptor",
"New York Nets",
"San Francisco 49ers",
"Dallas Mavericks"
)
for (team <- teams) {
team match {
case `matchNY` => println("Go New York.")
case _ => println("Boo")
}
}
Note-1: The usage of backticks is explained here @ http://alvinalexander.com/scala/scala-unreachable-code-due-to-variable-pattern-message
Upvotes: 2
Views: 1735
Reputation: 16255
I am assuming you meant
val matchNY = "^.*New.*$".r
and not ^.New.$
, if you were expecting to match strings containing New
.
In Scala, a block of case
statements can be thought of as a sequence
of partial functions.
In your example,
case `matchNY` => // ...
Translates to something like:
case x if x == matchNY => // ..
So that will try to match the String
"Toronto Raptor"
with the Regexp
object ^.*New.*$
using equality:
"Toronto Raptor" == ("^.*New.*$".r)
Which doesn't match because a String
and a Regexp
object are 2 different things.
The same goes for any of the other String
s in the list:
"New York Nets" != ("^.*New.*$".r)
Which doesn't match either. The way to use a regexp as a match in a case statement is:
case matchNY() => // .... Note the ()
Which, under the hood is (roughly) equivalant to something like
case x matchNY.unapplySeq(x).isDefined => // ...
Regexps in case statements are implemented as Extractor Objects with
an unapplySeq
method. The last expression shows what the previous
translates into.
If matchNY had a capture such as:
val matchNY = "^.*New York\s(.*)$".r
Then you could use it to extract the captured match:
case matchNY(something) => // 'something' is a String variable
// with value "Nets"
Side Note
Your example could be condensed to
teams foreach {
case matchNY() => println("Go New York.")
case _ => println("Boo")
}
Upvotes: 5
Reputation: 8821
Yes, it is working properly. The magic behinds pattern matching is something called extractors.
If you dig through the ScalaDoc of Regex, you will see that it only defined unapplySeq
, but not unapply
.
That means if you want use Regex at Pattern Matching, you should do the following (note the parentheses after matchNY) :
val matchNY = "^.*New.*$".r
val teams = List(
"Toronto Raptor",
"New York Nets",
"San Francisco 49ers",
"Dallas Mavericks"
)
for (team <- teams) {
team match {
case matchNY() => println("Go New York.")
case _ => println("Boo")
}
}
Otherwise, you are simply checking if the elements in the list is == matchNY
, which is not what you want anyway.
Upvotes: 4
Reputation: 13959
In your for loop you're literally checking if each item in the list of teams
is equal to the regex matchNY
and every item in the list is checked not just "Toronto Raptor". This is equivalent to your for loop:
for (team <- teams) {
if (team == matchNY) println("Go New York.")
else println("Boo")
}
Which breaks down to this:
if ("Toronto Raptor" == matchNY) println("Go New York.") else println("Boo")
if ("New York Nets" == matchNY) println("Go New York.") else println("Boo")
if ("San Francisco 49ers" == matchNY) println("Go New York.") else println("Boo")
if ("Dallas Mavericks" == matchNY) println("Go New York.") else println("Boo")
What I think your looking for is if something matches you're regex. You can do something like this:
for (team <- teams) {
matchNY.findFirstMatchIn(team) match {
case Some(teamMatch) => {
println("Go New York.")
println(teamMatch)
}
case _ => {
println("Boo")
println(team)
}
}
}
Which prints out:
Boo
Toronto Raptor
Go New York.
New York Nets
Boo
San Francisco 49ers
Boo
Dallas Mavericks
Upvotes: 1