2016-09-15 10 views
1

Работа с scala ClassTags Я видел, что classTag.runtimeClass.isInstance не работает должным образом, когда вы используете его с объектами AnyVal. Вот фрагмент, где вы можете проверить его. Любые идеи сделать эту работу для объектов 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") 
} 

КСТАТИ Я работаю с Scala 2.10

+0

это ошибка scala? – Mikel

+0

Использовать isInstanceOf вместо isInstance http://stackoverflow.com/questions/26168721/difference-between-isinstance-and-isinstanceof – Samar

+0

Я не могу использовать value.isInstanceOf [U], потому что это общий тип, поэтому мне нужно сделать использование classtag (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 принимает Object. classOf[Double] представляет собой «класс» примитива JVM doubleclassTag[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]) 

Конечно, это может Не указывайте разницу между Double и java.lang.Double на вашей карте, потому что эта разница не существует (кроме времени компиляции).

+0

Есть ли способ реализовать эту проверку для объектов AnyVal? – Mikel

+0

Я добавил решение. –

+0

Спасибо, это сработало! Я удивлен, что это сложное решение - единственный способ сделать это ... – Mikel

 Смежные вопросы

  • Нет связанных вопросов^_^