I have a map with a getter method. The key is always a String, the value is Any. I want to allow the caller to use a method like the followings
get[Int](k: String)
get[Boolean](k:String)
and inside this method convert the string to the specific type specified by the user. The immediate solution came to my mind was
def get[T](k: String): T = k.asInstanceOf[T]
which does not work. Then I tried with
def cast[T](x: String, classTag: ClassTag[T]): T = classTag match {
case Int => x.toInt
case Boolean => x.toBoolean
...
}
which does not compile. I am not sure this is even possible. Any idea or I need to write all the methods I want? For example
def getInt(k: String): Int
def getBoolean(k: String): Boolean
...
This is a classical use case for typeclass pattern widely used in scala. I assume that you have a custom implementation of Map
and get
method.
trait Converter[T]{ // typeclass
def convert(t:String):T
}
implicit object ToIntConverter extends Converter[Int] {
def convert(t:String):Int = t.toInt
}
implicit object ToBooleanConverter extends Converter[Boolean] {
def convert(t:String):Boolean = t.toBoolean
}
// vvv approach bellow works starting from scala 2.12 vvv
//
// implicit val ToBooleanConverter: Converter[Boolean] = s => s.toBoolean
// implicit val ToIntConverter : Converter[Int] = s => s.toInt
def get[T](k:String)(implicit cv: Converter[T]):T= cv.convert(k)
println(get[Int]("1"))
println(get[Boolean]("true"))
I got the below to work.
val anyMap: Map[String, Any] = Map(
"a" -> 1,
"b" -> true
)
def getInst[T](amap: Map[String, Any])(k: String): T = amap.get(k) match {
case Some(thing) => thing.asInstanceOf[T]
case None => throw new IllegalArgumentException
}
getInst[Int](anyMap)("a")
getInst[Boolean](anyMap)("b")
It's not very safe to have something like Map[String, Any] as the cast might fail. Probably best to introduce some ad-hoc polymorphism in your map (not sure).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With