Casting String to Int using scala extractors

vikraman picture vikraman · Feb 9, 2013 · Viewed 8.9k times · Source

I am trying to cast a String to Int using extractors. My code looks as follows.

object Apply {
  def unapply(s: String): Option[Int] = try {
    Some(s.toInt)
  } catch {
    case _: java.lang.Exception => None
  }
}

object App {
  def toT[T](s: AnyRef): Option[T] = s match {
    case v: T => Some(v)
    case _ => None
  }
  def foo(param: String): Int = {
    //reads a Map[String,String] m at runtime
    toT[Int](m("offset")).getOrElse(0)
  }
}

I get a runtime error: java.lang.String cannot be cast to java.lang.Integer. It seems the extractor is not being used at all. What should I do?

Edit: My use case is as follows. I am using play and I want to parse the query string passed in the url. I want to take the query string value (String) and use it as an Int, Double etc. For example,

val offset = getQueryStringAs[Int]("offset").getOrElse(0)

Answer

drexin picture drexin · Feb 9, 2013

I think the biggest problem here is, that you seem to confuse casting and conversion. You have a Map[String, String] and therefore you can't cast the values to Int. You have to convert them. Luckily Scala adds the toInt method to strings through implicit conversion to StringOps.

This should work for you:

m("offset").toInt

Note that toInt will throw a java.lang.NumberFormatException if the string can not be converted to an integer.

edit:

What you want will afaik only work with typeclasses.

Here is an example:

trait StringConverter[A] {
  def convert(x: String): A
}

implicit object StringToInt extends StringConverter[Int] {
  def convert(x: String): Int = x.toInt
}

implicit object StringToDouble extends StringConverter[Double] {
  def convert(x: String): Double = x.toDouble
}

implicit def string2StringConversion(x: String) = new {
  def toT[A](implicit ev: StringConverter[A]) = ev.convert(x)
}

usage:

scala> "0.".toT[Double]
res6: Double = 0.0