Scala pattern matching variable binding

2019-07-25 03:40发布

问题:

Why can't I bind the variable in @-style when the extractor return Option[<Type>]? I.e. this one does not work:

object IsUpperCase {
  def unapply(s: String): Option[String] = {
    if (s.toUpperCase() == s) {
      Some(s)
    } else {
      None
    }
  }
}

val s = "DuDu@qwadasd.ru"
s match {
  case u @ IsUpperCase() => println("gotcha!") // what? "wrong number of arguments for object IsUpperCase"?
  case _ => 
}

But this one works!

val s = "DuDu@qwadasd.ru"
s match {
  case IsUpperCase(u) => println("gotcha!")
  case _ => 
}

From the other hand, if IsUpperCase looks like this:

object IsUpperCase {
  def unapply(s: String): Boolean = {
    return s.toUpperCase() == s
  }
}

Then the first example works, and the second does not! Why is it this way?

回答1:

what? "wrong number of arguments for object IsUpperCase"?

case u @ IsUpperCase() => println("gotcha!")

Well, yes. The return type of unapply is Option[String], which means the pattern match of IsUpperCase must accept a parameter, like this:

case u @ IsUpperCase(_) => println("gotcha!") // I don't care about the parameter

The unapply definition that fits the first pattern is this:

object IsUpperCase {
  def unapply(s: String): Boolean = s.toUpperCase() == s
}

That can be used to pattern match against IsUpperCase().



回答2:

Because for the first example you need to write something like case u @ IsUpperCase(v) => or case u @ IsUpperCase(_) =>, which means "match IsUpperCase(v) and if it succeeds bind the original string to u".