你在混合类和类型的定义。 getClass
返回类元数据。 A TypeTag
包含类型元数据。他们是不同的东西。例如,String
,List
,Map
是类别,但List[Int]
和Map[Int, String]
是类型。例如,将一个类与一个类型进行比较通常没有意义,因为您可能会比较List
与List[Int]
之类的内容。
你可以把它工作中使用ClassTag
,它的提取:
import scala.reflect.ClassTag
val validMetadata: Map[String, Any] = Map(
"string" -> "this is a string",
"int" -> 12,
"double" -> 12.12
)
def getMetadata[T](key: String)(implicit tag: ClassTag[T]): Option[T] =
validMetadata.get(key) match {
case Some(tag(scalar)) => Option(scalar)
case _ => None
}
scala> getMetadata[Int]("int")
res1: Option[Int] = Some(12)
scala> getMetadata[Int]("string")
res2: Option[Int] = None
scala> getMetadata[String]("string")
res3: Option[String] = Some(this is a string)
但是,这可能会因使用类型参数的类。例如,如果你改变validMetadata
的定义:
val validMetadata: Map[String, Any] = Map(
"ints" -> List(1, 2, 3),
"strings" -> List("a", "b", "c")
)
scala> getMetadata[List[String]]("ints")
res5: Option[List[String]] = Some(List(1, 2, 3)) // No!!
的List
类型参数被擦除。 TypeTag
将允许您保存所有类型的信息,但是,一旦您的数据存储在Map[String, Any]
中,所有类型的信息都将丢失,因此TypeTag
无法提供帮助。为了使用它,你就必须从根本上您的Map
更改为类似:
import scala.reflect.runtime.universe._
case class Tagged[A](value: A)(implicit val tag: TypeTag[A])
val validMetadata: Map[String, Tagged[_]] = Map(
"ints" -> Tagged(List(1, 2, 3)), // Allows us to save type information at compile time, to carry over to run time
"strings" -> Tagged(List("a", "b", "c"))
)
def getMetadata[T](key: String)(implicit tag: TypeTag[T]): Option[T] =
validMetadata.get(key) match {
case Some(tagged) if(tag.tpe =:= tagged.tag.tpe) => Option(tagged.value.asInstanceOf[T])
case _ => None
}
scala> getMetadata[List[String]]("ints")
res6: Option[List[String]] = None
scala> getMetadata[List[String]]("strings")
res7: Option[List[String]] = Some(List(a, b, c))
这是笨重,但是不受其他可能使用非类型化Map
时恢复该深度的类型信息。根据您的要求,您可能希望看看类似shapelessHMap
的类型安全。
是的。更新了原来的问题。感谢您指出了这一点。 – threejeez