Overriding unapply method

2020-03-20 06:07发布

问题:

I have a case from a library class and I want to override unapply method to reduce the number of parameters I need to pass to do pattern matching against it. I do this:

object ws1 {
  // a library class
  case class MyClass(a: Int, b: String, c: String, d: Double /* and many more ones*/)

  // my object I created to override unapply of class MyClass
  object MyClass {
    def unapply(x: Int) = Some(x)
  }

  val a = new MyClass(1, "2", "3", 55.0 /* and many more ones*/)
  a match {
    case MyClass(x /*only the first one is vital*/) => x  // java.io.Serializable = (1,2,3,55.0)
    case _ => "no"
  }
}

But I want it to return just 1. What's wrong with this?

回答1:

case class MyClass(a: Int, b: String, c: String, d: Double /* and many more ones*/)
object MyClassA {
   def unapply(x: MyClass) = Some(x.a)
}

val a = new MyClass(1, "2", "3", 55.0 /* and many more ones*/)

a match {
    case MyClassA(2) => ??? // does not match
    case MyClassA(1) => a   // matches
    case _ => ??? 
}

You cannot define your custom unapply method in the MyClass object, because it would have to take a MyClass parameter, and there's already one such method there – one generated automatically for the case class. Therefore you have to define it in a different object (MyClassA in this case).

Pattern matching in Scala takes your object and applies several unapply and unapplySeq methods to it until it gets Some with values that match the ones specified in the pattern.
MyClassA(1) matches a if MyClassA.unapply(a) == Some(1).

Note: if I wrote case m @ MyClassA(1) =>, then the m variable would be of type MyClass.

Edit:

a match {
    case MyClassA(x) => x  // x is an Int, equal to a.a
    case _ => ??? 
}


回答2:

I would ditch the overloaded unapply and just use the following for the match:

a match {
  case MyClass(x, _, _, _) => x  // Result is: 1
  case _ => "no"
}

EDIT :

If you really want to avoid the extra underscores, I think you'll need to look at something like:

a match {
  case x:MyClass => x.a
  case _ => "no"
}


标签: scala