mercredi 3 août 2016

How to use type information from pattern matching?

I have the following setup:

trait TypeA { override def toString() = "A" }
trait TypeB { override def toString() = "B" }
trait TypeC { override def toString() = "C" }

def foo[T](t: T) = println(t)

Now I can do something like this:

val valueB: TypeB = new TypeB {}

val typedValue = valueB match {
  case t: TypeA => foo(t)
  case t: TypeB => foo(t)
  case t: TypeC => foo(t)
}
// prints "B"

If I want to generalize this pattern matching block, I can simply do:

val typedValue = valueB match {
  case t => foo(t)
}

and it will work. However, in my real use case I need to explicitly state the type information when invoking the method because there is no function argument to infer it from. So if foo() was a generic method parameterized with type parameter T, but without actual parameters of that type to infer from, can I generalize this into a pattern matching with just one case statement (probably using the Reflection API)?

val typedValue = valueB match {
  case t: TypeA => foo[TypeA]()
  case t: TypeB => foo[TypeB]()
  case t: TypeC => foo[TypeC]()
  ...
}

(For those who want the real code:)

I'm working with Play's JSON library and I would like to generalize this:

val realValue = jsonValue match {
    case js: JsObject => js.as[JsObject].value
    case js: JsArray  => js.as[JsArray].value
    case js: JsString => js.as[JsString].value
    case js: JsNumber => js.as[JsNumber].value
    case js => js  
}

but I specifically did not want to simply paste this as a question in order to avoid Play-specific workarounds. I'm interested in the general principle for this kind of problem.





Aucun commentaire:

Enregistrer un commentaire