Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Scala: generic function to get a String converted

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
...
like image 838
alexlipa Avatar asked Dec 14 '18 17:12

alexlipa


2 Answers

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"))
like image 70
Bogdan Vakulenko Avatar answered Nov 05 '22 04:11

Bogdan Vakulenko


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).

like image 2
Zed Ekkes Avatar answered Nov 05 '22 04:11

Zed Ekkes