我需要构造一个大的HashMap,但是我不想手动将每个值输入到map中,这里有一个例子。
val codecs = HashMap(
"Foo" -> deriveEncoder[Foo],
"Bar" -> deriveEncoder[Bar],
"Qux" -> deriveEncoder[Qux],
)
deriveEncoder
是一个采用单个类型参数的函数。理想情况下,我想要以下内容:
val concreteClasses = List(Foo, Bar, Qux)
concreteClasses.foreach(T => codecs.put(T.name, deriveEncoder[T]))
这是不可能的,但有什么合理的替代方案呢?
理由还在于,它允许在对象构造期间传入类型列表,从而将实际类型与包含类本身的实现分离。
谢谢
目标是在运行时动态构造一个HashMap
,其中键是类型,但类型是编译时构造。TypeTag
是一种将编译时类型信息传输到运行时的方法。也许这样的事情是可能的
package example
import scala.collection.immutable.HashMap
import scala.reflect.runtime.universe
import scala.tools.reflect.ToolBox
import scala.reflect.runtime.universe._
case class Foo(i: Int)
case class Bar(i: Int)
case class Qux(i: Int)
trait Encoder[T] {
def encode(v: T): String
}
object Encoder {
def apply[T](implicit ev: Encoder[T]) = ev
implicit val fooEncoder: Encoder[Foo] = v => v.toString
implicit val barEncoder: Encoder[Bar] = v => v.toString
implicit val quxEncoder: Encoder[Qux] = v => v.toString
}
object forEachOnTypes extends App {
val concreteClasses = List(typeTag[Foo], typeTag[Bar], typeTag[Qux])
def encodersFor(tps: List[TypeTag[_]]) = {
val toolbox = universe.runtimeMirror(Thread.currentThread().getContextClassLoader).mkToolBox()
tps.map { tp =>
tp.tpe.typeSymbol.name.toString -> toolbox.eval(toolbox.parse(s"""example.Encoder[${tp.tpe}]""")).asInstanceOf[Encoder[_]]
}.to(HashMap)
}
val encoders = encodersFor(concreteClasses)
encoders("Foo")
}
但是我不知道这是否合理,因为我们必须利用asInstanceOf
encoders("Foo").asInstanceOf[Encoder[Foo]].encode(Foo(42))