Reputation: 5280
I am trying to define a map with a parameterized class as its key. But when I try to add to it I get a compiler error:
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
}
I get the following compiler error:
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
What is the correct way to extract my class as a key? It compiles fine if I use a concrete class for example:
map += classOf[A] -> n
Upvotes: 1
Views: 115
Reputation: 51683
You should add context bound ClassTag
and replace classOf[T]
with classTag[T].runtimeClass
.
classOf[T]
works with actual classes (that are known to be classes now, like classOf[Int]
, classOf[String]
etc). For type parameters (that will become class types when a method is called) you need class tags.
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
Upvotes: 2