Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to cast a variable to certain runtime type got from TypeCast in Scala

The asInstanceOf[T] works for "simple" case where the type T is given explicitly by code: e.g.

scala> val x: Any = 5
x: Any = 5

scala> x.asInstanceOf[Int]
res50: Int = 5

scala> val m1: Any = Map[String, Int]("a"->1, "b"->2)
m1: Any = Map(a -> 1, b -> 2)

scala> m.asInstanceOf[Map[String, Int]]
res51: Map[String,Int] = Map(a -> 1, 2 -> b)

scala> val m2: Any = Map[Any,Any]("a"->1, 2->"b")
m2: Any = Map(a -> 1, 2 -> b)

scala> m.asInstanceOf[Map[Any, Any]]
res52: Map[Any,Any] = Map(a -> 1, 2 -> b)

But when the type T is retrieved at runtime through TypeTags, asInstanceOf[T] does not work. For example:

scala> val intT = typeTag[Int].tpe
intT: reflect.runtime.universe.Type = Int

scala> x.asInstanceOf[intT]
<console>:12: error: not found: type intT
              x.asInstanceOf[intT]

The error says it clear that intT is not a type. So reflect.runtime.universe.Type is not a real type? How to cast a value to certain type using typeTag information?

like image 458
Causality Avatar asked Apr 01 '15 19:04

Causality


1 Answers

intT isn't a type, but an instance of Type. Confusing, for sure. I'm not sure if there is something built into the reflection API that does this, but you can easily write a method that will cast to A given an element Any and a TypeTag[A].

def cast[A](a: Any, tt: TypeTag[A]): A = a.asInstanceOf[A]

scala> val intT = typeTag[Int]
intT: reflect.runtime.universe.TypeTag[Int] = TypeTag[Int]

scala> val a: Any = 1
a: Any = 1

scala> cast(a, intT)
res101: Int = 1

Another variant using an implicit class:

implicit class TypeTagCast(a: Any) {
    def fromTypeTag[A](tt: TypeTag[A]): A = a.asInstanceOf[A]
 }

scala> a.fromTypeTag(intT)
res106: Int = 1
like image 184
Michael Zajac Avatar answered Nov 13 '22 17:11

Michael Zajac