Scala 使用ClassTag查看我拥有的是否与模板类型相同

Scala 使用ClassTag查看我拥有的是否与模板类型相同,scala,Scala,我正在尝试编写一个模板函数,它根据类型从映射中检索值。如果模板类型与映射中的类型不匹配,则应返回None: val validMetadata: Map[String, Any] = Map( "string" -> "this is a string", "int" -> 12, "double" -> 12.12 ) import scala.reflect.runtime.universe._ private def getMetadata[T](key:

我正在尝试编写一个模板函数,它根据类型从映射中检索值。如果模板类型与映射中的类型不匹配,则应返回None:

val validMetadata: Map[String, Any] = Map(
  "string" -> "this is a string",
  "int" -> 12,
  "double" -> 12.12
)

import scala.reflect.runtime.universe._
private def getMetadata[T](key: String)(implicit tag: TypeTag[T]): Option[T] =
  validMetadata.get(key) match {
    case Some(scalar) if scalar.getClass == tag.tpe => Option(scalar)
    case _ => None
  }

getMetadata[Int]("int") // should return Option(12)
getMetadata[Int]("string") // should return None

这不起作用,我尝试过的数百种变体中的任何一种也不起作用。你知道我如何做到这一点吗?

你把类和类型的定义混为一谈了
getClass
返回类元数据。
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!!
列表
的类型参数被删除
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))

这很笨重,但在使用未键入的
映射时,无法恢复此深度的类型信息。根据您的要求,您可能需要研究类似于
HMap
的类型安全问题。

是的。更新了原始问题。谢谢你指出这一点。谢谢你的精彩描述!