J Pullar
J Pullar

Reputation: 1935

Scala matching, resolving the same variable from two different patterns

Say I have the following

case class IntWrap(value:Int)

I would like to extract the same variable from two cases as follows:

x match {
  case value:Int | IntWrap(value) => dosomethingwith(x)
  case _ => ???
}

but the only way I have been able to do this is as:

x match {
  case value:Int => dosomethingwith(x)
  case IntWrap(value) => dosomethingwith(x)
  case _ => ???
}

Is there a better way, as in my real life case dosomething is actually a large block of code which is not so easy to encapsulate.

Upvotes: 1

Views: 577

Answers (3)

rarry
rarry

Reputation: 3573

I came up with sth a little bit different, but it may help you avoid duplicates:

  case class IntWrap(value: Int)
  implicit def intWrapToInt(intWrap: IntWrap) = intWrap.value

  def matchInt(x: AnyVal) = x match {
    case i: Int => println("int or intWrap")
    case _ => println("other")
  }

  //test
  matchInt(IntWrap(12))          //prints int or intWrap
  matchInt(12)                   //prints int or intWrap
  matchInt("abc")                //prints other

It won't work for every reference, though. So, be careful.

Upvotes: 0

Malte Schwerhoff
Malte Schwerhoff

Reputation: 12852

If it is really the case that you want to do something with x, not with the extracted value, then the following would work:

case class IntWrap(value:Int) // extends T

def dosomethingwith(x: Any) = x

val x: Any = IntWrap(101)

x match {
  case _: Int | _: IntWrap => dosomethingwith(x)
  case _ => ???
}


If you actually want to work with the extracted value, you could factor out the corresponding match block into its own extractor and reuse that wherever necessary:

x match {
  case Unwrap(value) => dosomethingwith(value)
  case _ => ???
}

object Unwrap {
  def unapply(x: Any) = x match {
    case x: Int => Some((x))
    case IntWrap(value) => Some((value))
    case _ => None
  }
}

Upvotes: 2

cmbaxter
cmbaxter

Reputation: 35463

I honestly don't see an issue with the way you are doing things. As long as dosomethingwith is a separate function then I don't see any issues with duplicate code. If your code looked like this then I don't see any need to come up with other solutions:

def foo(x:Any){
  x match {
    case value:Int => dosomethingwith(value)
    case IntWrap(value) => dosomethingwith(value)
    case _ => ???
  }
}

def dosomethingwith(x:Int){
  //do something complicated here...
}

Upvotes: 0

Related Questions