I have a map of type Map[_, Any]
, and I want to extract the values in their native format (without resorting to .asInstanceOf[_]
).
Something like this...
val m: Map[String, Any] = Map("i" -> 1, "s" -> "test")
val i: Option[Int] = m.get("i")
val s: Option[String] = m.get("s")
Obviously that fails.
I don't like this approach, but I was thinking I could do something like this... but even this still comes out as Any
instead of Int
or String
.
trait MyType[A] {
def value: A
}
implicit class MyInt(i: Int) extends MyType[Int] { def value: Int = i }
implicit class MyString(s: String) extends MyType[String] { def value: String = s }
val m: Map[String, MyType[_]] = Map("i" -> 1, "s" -> "test")
val i: Option[Int] = m.get("i").map(_.value)
val s: Option[String] = m.get("s").map(_.value)
Then I thought maybe some wrapper around the Map
...
case class MyMap(m: Map[String, Any]) {
def get[A](k: String)(implicit ev: Option[Any] => Option[A]): Option[A] = m.get(k)
}
But that STILL comes out as Any
. I just can't figure out how to convert Any => native.
So my questions are...
Thanks!
You cannot guess the runtime type for the reasons that have already been explained in the comments - this information is not there, once it's Any
, all type information is lost, there is nothing you can do about it.
So, you'll have to provide the expected type yourself. How about an .as[T]
helper method?
// This code is specifically for 2.11, please don't use it for more recent versions,
// see link below.
val m: Map[String, Any] = Map("i" -> 1, "s" -> "test")
import scala.reflect.{ ClassTag, classTag }
implicit class As(a: Any) {
def as[T](implicit ct: ClassTag[T]): Option[T] = ct.unapply(a)
}
println(m("i").as[Int].map(_ + 41).get)
println(m("s").as[String].map("This is a " + _).get)
This will print
42
This is a test
Brief explanation:
As
wrapper "pimps" all the objects, and attaches an .as
method to everything.unapply
does the checking, the casting, and the wrapping in an Option
.It will not work for generic types like List[Int]
vs. List[String]
etc, because this information is simply not available at runtime.
EDIT: Thanks @MarioGalic for greatly simplifying the solution.