Приведение строки к Int с использованием экстракторов scala
Я пытаюсь разыграть String
в Int
используя экстракторы. Мой код выглядит следующим образом.
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)
}
}
Я получаю ошибку во время выполнения: java.lang.String cannot be cast to java.lang.Integer
, Кажется, экстрактор вообще не используется. Что я должен делать?
Изменить: Мой вариант использования заключается в следующем. Я использую play и хочу проанализировать строку запроса, переданную в URL. Я хочу взять значение строки запроса (String) и использовать его как Int, Double и т. Д. Например,
val offset = getQueryStringAs[Int]("offset").getOrElse(0)
2 ответа
I think the biggest problem here is, that you seem to confuse casting and conversion. У тебя есть 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.
Это должно работать для вас:
m("offset").toInt
Обратите внимание, что toInt
бросит java.lang.NumberFormatException
if the string can not be converted to an integer.
редактировать:
What you want will afaik only work with typeclasses.
Вот пример:
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)
}
использование:
scala> "0.".toT[Double]
res6: Double = 0.0
В вашем коде есть проблема, для которой вы должны были получить предупреждения компилятора:
def toT[T](s: AnyRef): Option[T] = s match {
case v: T => Some(v) // this doesn't work, because T is erased
case _ => None
}
Теперь... где следует Apply
был использован? Я вижу, что заявлено, но я не вижу, чтобы это использовалось где-либо.
РЕДАКТИРОВАТЬ
О предупреждении смотрите в обсуждениях по поводу стирания типов в переполнении стека. Например, этот ответ я написал о том, как его обойти - хотя сейчас он устарел в Scala 2.10.0.
Чтобы решить вашу проблему, я бы использовал классы типов. Например:
abstract class Converter[T] {
def convert(s: String): T
}
object Converter {
def toConverter[T](converter: String => T): Converter[T] = new Converter[T] {
override def convert(s: String): T = converter(s)
}
implicit val intConverter = toConverter(_.toInt)
implicit val doubleConverter = toConverter(_.toDouble)
}
Затем вы можете переписать свой метод так:
val map = Map("offset" -> "10", "price" -> "9.99")
def getQueryStringAs[T : Converter](key: String): Option[T] = {
val converter = implicitly[Converter[T]]
try {
Some(converter convert map(key))
} catch {
case ex: Exception => None
}
}
В использовании:
scala> getQueryStringAs[Int]("offset")
res1: Option[Int] = Some(10)
scala> getQueryStringAs[Double]("price")
res2: Option[Double] = Some(9.99)