Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I use a class variable in a Scala match statement?

Tags:

class

scala

Say I have something like this:

obj match {
    case objTypeOne : TypeOne => Some(objTypeOne)
    case objTypeTwo : TypeTwo => Some(objTypeTwo)
    case _ => None
}

Now I want to generalise, to pass in one of the types to match:

obj match {
    case objTypeOne : clazz => Some(objTypeOne)
    case objTypeTwo : TypeTwo => Some(objTypeTwo)
    case _ => None
}

But this isn't allowed, I think for syntactic rather than semantic reasons (although I guess also that even though the clazz is a Class[C] the type is erased and so the type of the Option will be lost).

I ended up with:

if(clazzOne.isAssignableFrom(obj.getClass)) Some(clazz.cast(obj))
if(obj.isInstanceOf[TypeTwo]) Some(obj.asInstanceOf[TypeTwo])
None

I just wondered if there was a nicer way.

like image 219
Dan Gravell Avatar asked Dec 31 '25 09:12

Dan Gravell


2 Answers

You could define an extractor to match your object:

class IsClass[T: Manifest] {
  def unapply(any: Any): Option[T] = {
    if (implicitly[Manifest[T]].erasure.isInstance(any)) {
       Some(any.asInstanceOf[T])
    } else {
       None
    }
  }
}

So let's test it:

class Base { def baseMethod = () }
class Derived extends Base

val IsBase = new IsClass[Base]

def test(a:Any) = a match {
    case IsBase(b) => 
      println("base")
      b.baseMethod
    case _ => println("?")
  }

test(new Base)
test(1)

You will have to define a val for your extractor, you can't inline IsBase, for example. Otherwise it would be interpreted as an extractor.

like image 80
mkneissl Avatar answered Jan 02 '26 10:01

mkneissl


You could use pattern guards to achieve that. Try something like this:

obj match {
    case objTypeTwo : TypeTwo => Some(objTypeTwo)
    case objTypeOne if clazz.isAssignableFrom(objTypeOne.getClass) => Some(clazz.cast(objTypeOne))
    case _ => None
}
like image 43
axel22 Avatar answered Jan 02 '26 10:01

axel22



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!