2016-09-15 52 views
1

使用Scala ClassTags工作工作,我已經看到,當你與AnyVal對象使用classTag.runtimeClass.isInstance不能正常工作。這裏有一個你可以測試的片段。任何想法使這項工作AnyVal對象?ClassTag.runtimeClass.isInstance不會爲AnyVal

import scala.reflect.ClassTag 
import scala.reflect.runtime.{universe => ru} 
object Test { 
    def extractField[U: ru.TypeTag](json: Map[String, Any], field: String)(implicit classTag: ClassTag[U]): Option[U] = { 
    json.get(field) match { 
     case Some(value) => 
     if(classTag.runtimeClass.isInstance(value)) 
      Some(value.asInstanceOf[U]) 
     else { 
      None 
     } 
     case _ => 
     None 
    } 
    } 
    val map: Map[String,Any] = Map("k1" -> 2.0, "k2" -> "v") 
    extractField[Double](map,"k1") // RETURNS NONE 
    extractField[String](map,"k2") // RETURNS Some("v") 
} 

BTW,我使用Scala 2.10

+0

這是一個斯卡拉錯誤? – Mikel

+0

使用isInstanceOf代替isInstance http://stackoverflow.com/questions/26168721/difference-between-isinstance-and-isinstanceof – Samar

+0

我不能使用value.isInstanceOf [U],因爲它是一個通用型的,所以我需要做使用經驗值(value.isInstanceOf [U]未被檢查,因爲被刪除消除) – Mikel

回答

2

在這裏工作是顯示同一個問題要簡單得多代碼:

val c = classTag[Double].runtimeClass 
println(c) // double 
println(c == classOf[Double]) // true 
println(c.isInstance(0.0)) // false 

isInstance需要一個ObjectclassOf[Double]代表JVM原語double(和classTag[Double].runtimeClass是相同的)的「類」。由於對象不能是原始的,因此classOf[Double].isInstance(something)將始終爲假。

Map[String, Any]實際上並不包含AnyVal S,但只有對象;當你寫

val map: Map[String,Any] = Map("k1" -> 2.0, "k2" -> "v") 

2.0自動裝箱爲java.lang.Double,因此您的代碼正確的告訴你沒有這個鍵下沒有Double。但是,你可以寫一個簡單的輔助功能(我認爲這是在標準庫中的某個地方,但不記得在哪裏):

private val boxedClasses = 
    Map[Class[_], Class[_]](classOf[Double] -> classOf[java.lang.Double], ...) // the rest of AnyVal classes 
def boxed(c: Class[_]) = boxedClasses.getOrElse(c, c) 

,然後在case Some(value)

if(boxed(classTag.runtimeClass).isInstance(value)) 
    Some(value.asInstanceOf[U]) 

當然它可以不會告訴你地圖上的Doublejava.lang.Double之間的區別,因爲這個區別不存在(編譯時除外)。

+0

有沒有一種方法可以實現對AnyVal對象的檢查? – Mikel

+0

我已經添加了一個解決方案。 –

+0

謝謝,它工作!我很驚訝,這棘手的解決辦法是做到這一點的唯一途徑... – Mikel