gpt4 book ai didi

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

转载 作者:行者123 更新时间:2023-12-02 21:03:26 24 4
gpt4 key购买 nike

我正在尝试编写一个模板函数,该函数根据类型从 Map 检索值。如果模板类型与 Map 中的类型不匹配,则应返回 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 包含类型元数据。它们是不同的东西。例如,StringListMap 是类,但 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时,不可能恢复这种类型信息的深度。根据您的要求,您可能需要查看类似 shapeless 的内容HMap 用于类型安全。

关于scala - 使用ClassTag查看我拥有的是否与模板类型相同,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37174357/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com