2

エクストラクタ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)
4

2 に答える 2

4

ここでの最大の問題は、キャストと変換を混同しているように見えることだと思います。を持っているMap[String, String]ため、値をにキャストすることはできませんInt。それらを変換する必要があります。幸いなことに、ScalaはtoIntStringOpsへの暗黙の変換を通じて文字列にメソッドを追加します。

これはあなたのために働くはずです:

m("offset").toInt

文字列を整数に変換できない場合は、toIntがスローされることに注意してください。java.lang.NumberFormatException

編集

必要なものは、型クラスでのみ機能します。

次に例を示します。

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
于 2013-02-09T22:34:40.450 に答える
1

コードに問題があり、コンパイラの警告を受け取る必要があります。

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?宣言されているのはわかりますが、どこでも使用されているのはわかりません。

編集

警告については、StackOverflowの型消去に関する説明をご覧ください。たとえば、私がそれを回避する方法について書いたこの回答は、Scala2.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)
于 2013-02-09T22:12:30.507 に答える