您如何使用迭代值作为类型参数在Scala中“遍历”类型列表?

问题描述 投票:0回答:1

我需要构造一个大型的HashMap,但是我不想手动将每个值输入到地图中,这是一个示例。

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]))

这是不可能的,但是对此有什么合理的选择?

理由还在于,它将允许在对象构造期间传递类型列表,将实际类型与包含类本身的实现脱钩。

谢谢

scala foreach types implicit
1个回答
0
投票

目标是在运行时动态构造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))
© www.soinside.com 2019 - 2024. All rights reserved.