Как вы 'foreach' над списком типов в Scala, используя повторное значение в качестве параметра типа? - PullRequest
0 голосов
/ 18 января 2020

Мне нужно создать большой 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]))

Это невозможно, но что было бы разумной альтернативой этому?

Причина также в том, что это позволило бы список типов для передачи во время создания объекта, развязывая фактические типы с реализацией самого содержащего класса.

Спасибо

1 Ответ

1 голос
/ 18 января 2020

Цель состоит в том, чтобы динамически создать 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))
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...