【问题标题】:How to manipulate a map using a parameterized class as the key如何使用参数化类作为键来操作地图
【发布时间】:2021-01-15 20:05:32
【问题描述】:

我正在尝试定义一个以参数化类为键的映射。但是当我尝试添加它时,我得到一个编译器错误:

trait MyTrait[T <: MyTrait[T]]

case class A(i: Int) extends MyTrait[A]
case class B(str: String) extends MyTrait[B]

var map = Map[Class[_ <: MyTrait[_]], Int]()

def update[T <: MyTrait[T]](n: Int) = {
    map += classOf[T] -> n  // Won't compile
}

我收到以下编译器错误:

  Expression does not convert to assignment because:  
    class type required but T found  
    expansion: map = map.+(classOf[T].<$minus$greater: error>(n))  
        map += classOf[T] -> n  

将我的课程提取为密钥的正确方法是什么?例如,如果我使用具体的类,它编译得很好:

    map += classOf[A] -> n

【问题讨论】:

  • 要使classOf 与泛型一起工作,您必须指定您希望在运行时拥有类型信息。通常你需要一些ClassTag 魔法。
  • 这里的问题是Ttype 而不是一个类,因此classOf 将不起作用。您将需要使用反射来提取该类型的类。
  • F-Bound 多态性、可变映射和想要使用类作为键之类的东西对我来说都是代码味道。请问您要解决的元问题是什么?

标签: scala types implicit f-bounded-polymorphism classtag


【解决方案1】:

您应该添加上下文绑定ClassTag 并将classOf[T] 替换为classTag[T].runtimeClass

classOf[T] 与实际类一起工作(现在已知是类,如classOf[Int]classOf[String] 等)。对于类型参数(调用方法时将成为类类型),您需要类标签。

def update[T <: MyTrait[T]: ClassTag](n: Int) = {
  val clazz = classTag[T].runtimeClass.asInstanceOf[Class[T]]
  map += clazz -> n
}

println(map) //HashMap()
update[A](1) 
println(map) //HashMap(class A -> 1)
update[B](2)
println(map) //HashMap(class A -> 1, class B -> 2)

https://docs.scala-lang.org/overviews/reflection/typetags-manifests.html

【讨论】:

    猜你喜欢
    • 2022-12-20
    • 2023-03-22
    • 2015-01-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-07-31
    • 2011-05-13
    相关资源
    最近更新 更多