Приведение строки к 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)
Другие вопросы по тегам