2013-02-09 59 views
2

我想使用提取器將String投射到Int。我的代碼如下所示。使用scala提取器將字符串投射到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中傳遞的查詢字符串。我想借此查詢字符串值(字符串),並把它作爲一個Int,雙等。例如,

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

爲什麼你希望它被使用? – pedrofurla 2013-02-09 22:11:10

+0

你用「隱式轉換」標記了這個問題,你的代碼沒有隱式轉換。 – pedrofurla 2013-02-09 22:12:22

+0

'T [T] ...案件v:T'將不起作用,T在擦除中丟失。 – pedrofurla 2013-02-09 22:13:00

回答

4

我認爲最大的問題在這裏,你似乎混淆鑄造和轉換。你有一個Map[String, String],因此你不能將值轉換爲Int。你必須轉換它們。幸運的是,Scala通過向StringOps的隱式轉換將字符串toInt添加到字符串中。

這應該爲你工作:

m("offset").toInt 

注意toInt將拋出一個java.lang.NumberFormatException如果不能將字符串轉換爲整數。

編輯

你想要什麼就會AFAIK只與類型類的工作。

下面是一個例子:

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 
+0

這很好,但我想要的是一種可以一般工作的toT [T]方法。 – vikraman 2013-02-09 22:37:09

+0

更新了我的文章 – drexin 2013-02-09 22:45:48

+0

好的,謝謝,這是否可以做到這一點?爲什麼不能匹配類型? – vikraman 2013-02-09 22:51:03

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應該在哪裏使用?我看到它宣佈,但我沒有看到它在任何地方使用。

編輯

關於警告,看看周圍類型擦除對堆棧溢出的討論。例如,this answer我寫過關於如何解決它 - 雖然現在已經棄用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) 
+0

剛纔說的那麼:P – pedrofurla 2013-02-09 22:13:22

+0

我確實得到了這個警告,無論如何都忽略了它,所以我應該怎麼做呢?理想情況下,我應該可以調用toT [Int],toT [Double]等,並且它們應該使用適當的unapply 。 – vikraman 2013-02-09 22:16:31