Scala - Extractor Objects confusion

2019-09-01 12:14发布

问题:

I am kind of confused about extractor and its using. I read Scala document and meet that one

object Twice {
  def apply(x: Int): Int = x * 2
  def unapply(z: Int): Option[Int] = if (z%2 == 0) Some(z/2) else None
}
object TwiceTest extends App {
  val x = Twice(21)  // x = 42
  x match { case Twice(n) => Console.println(n) } // prints 21
}`

As the above code print out, when we call x match {case Twice(n) ..., it means Twice(n) --> Twice.unapply(n) --> Twice.unapply(42) and get Some(n/2) --> Some(42/2) and plug result into n again, print out 21

If I change "unapply" as follow: def unapply(z: Int): Option[Int] = if (z%2 == 0) Some(z - 2) else None

What I get from the console is 40

So, do I understand it right?

回答1:

it means Twice(n) --> Twice.unapply(n) --> Twice.unapply(42)

No, Twice(n) is a pattern (here; it can also be used as an expression, but with a different meaning), and Twice.unapply(n) is an expression. And it's an expression which makes no sense here, because you don't have a value for n yet! Twice.unapply(x) is called instead.

x match { case Twice(n) => ...expression_using_n; ...other cases } is basically the same as

Twice.unapply(x) match { 
  case Some(n) => ...expression_using_n
  case None => x match { ...other cases }
}

Or to remove circularity, since Some itself is an extractor object:

val unapplied = Twice.unapply(x)
if (unapplied.isDefined) {
  val n = unapplied.get
  ...expression_using_n
} else 
  x match { ...other cases }