Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Scala - extractor unapply confusion

I'm attempting to write an extractor(s) for use in matching against a multiple parameter case class. Simplified example:

case class X(p1: String, p2: Int)

I'd like each extractor objects to define a fixed value for p1, and p2 is defined on use. (A,B, etc cannot be a case class and subclass X, and I would also like to use X(,) as a case) Example with apply method:

object A {
  def apply(p2: Int): X = X("A", p2)
}

object B {
  def apply(p2: Int): X = X("B", p2)
}

...

For pattern matching, I would like them to match like this:

X("A", 2) match {
  case A(2) => true // <- should match: p1="A" and p2=2
  case A(_) => true // <- should match: p1="A" and p2=_
  case X("A", _) => true // <- should match: p1="A" and p2=_
  case A(1) => false // <- should not match
  case B(2) => false // <- should not match: p1="B" and p2=2
}

I know I need to define unapply method in A, B, etc., but I'm thoroughly confused what the signature and logic should be:

object A {
  def unapply(x: ???): Option[???] = {
    ???
  } 
}

Assistance, please?

like image 848
7zark7 Avatar asked Jun 28 '12 05:06

7zark7


1 Answers

unapply takes an Any and returns an Option of whatever you want to extract. In your case this would be:

scala> case class X(p1: String, p2: Int)
defined class X

scala> object A {
     |   def unapply(target: Any): Option[Int] =
     |     PartialFunction.condOpt(target) {
     |       case X("A", p2) => p2
     |     }
     | }
defined module A

scala> val A(x) = X("A", 1)
x: Int = 1

scala> val A(x) = X("B", 1)
scala.MatchError: X(B,1) (of class X)
...

But to be honest, the example you came up with could be rewritten without A and B:

X("A",2) match {
  case X("A", 2) => true
  case X("A", 1) => false
  case X("A", _) => true
  case X("B", 2) => false
}
like image 177
Heiko Seeberger Avatar answered Sep 19 '22 23:09

Heiko Seeberger