У меня есть две черты, и их объекты экземпляра, определенная следующим образом:Scala отражения разрешить общие черты от имени во время выполнения
package reflection
trait Monoid[T] {
def id: T
def op(lhs: T, rhs: T): T
}
trait ADTHelper[T]{
type V
def create(value: V): T
def get(adt: T): Any
}
case class Avg(avg: Double, n: Int)
object AvgMonoid extends Monoid[Avg] with ADTHelper[Avg]{
override def id: Avg = Avg(0, 0)
override def op(lhs: Avg, rhs: Avg): Avg =
Avg((lhs.avg * lhs.n + rhs.avg * rhs.n)/(lhs.n + rhs.n), lhs.n + rhs.n)
override type V = Double
override def create(value: Double): Avg = Avg(value, 1)
override def get(adt: Avg): Any = adt.avg
}
object MinMonoid extends Monoid[Double] with ADTHelper[Double]{
override def id: Double = Double.MaxValue
override def op(lhs: Double, rhs: Double): Double = if(lhs < rhs) lhs else rhs
override type V = Double
override def create(value: Double): Double = value
override def get(adt: Double): Any = adt
}
Я хочу, чтобы получить моноидные экземпляры во время выполнения от имен. Forexample, если я говорю "min"
, я хочу MinMonoid
объект, "avg"
должен дать AvgMonoid
объект и т.д. Так что я есть следующие настройки:
object Test extends App {
val AGGREGATORS_NAME_DICT = Map(
"avg" -> "reflection.AvgMonoid",
"min" -> "reflection.MinMonoid",
"max" -> "reflection.MaxMonoid"
)
val AGGREGATORS_ADT_DICT = Map(
"avg" -> "reflection.Avg",
"min" -> "scala.Double",
"max" -> "scala.Double"
)
val mirror = runtimeMirror(getClass.getClassLoader)
def stringToTypeTag[A](name: String): TypeTag[A] = {
val tpe = mirror.staticClass(name).selfType
TypeTag(mirror, new api.TypeCreator {
def apply[U <: api.Universe with Singleton](m: api.Mirror[U]) =
if (m eq mirror) tpe.asInstanceOf[U#Type]
else throw new IllegalArgumentException(s"Type tag defined in $mirror cannot be migrated to other mirrors.")
})
}
def resolve[T](fname: String): Option[Monoid[T] with ADTHelper[T]] = for {
monoidName <- AGGREGATORS_NAME_DICT.get(fname)
adtName <- AGGREGATORS_ADT_DICT.get(fname)
tag <- Option{stringToTypeTag[T](adtName)}
instance <- Option {
mirror
.reflectModule(mirror.staticModule(monoidName))
.instance
.asInstanceOf[Monoid[T] with ADTHelper[T]]
}
} yield instance
}
Теперь проблема: я могу сделать:
println(resolve("min").get.op(1.0, 2.0))
но я не могу сделать:
val monoid = resolve("min").get
println(monoid.op(1.0, 2.0))
, так как тип monoid
позже есть Monoid[Nothing] with ADTHelper[Nothing]
. Я не могу разрешить базовый тип T
из trait Monoid[T]
и trait ADTHelper[T]
с использованием метода resolve
, с которым я столкнулся. Как я могу изменить функцию resolve
так, чтобы она разрешала черты с базовым типом T
???
Я знаю, если я позвоню с помощью resolve[Double](...)
, он будет работать, но я хочу, чтобы это разрешалось во время выполнения из AGGREGATORS_ADT_DICT
.
Спасибо за комментарий. Так что это из-за стирания в JVM, верно? Любой альтернативный подход, который вы можете предложить для этого? – bistaumanga
На самом деле, я ant, чтобы получить эти Карты из файла конфигурации. Я не уверен, что использование макросов будет работать, потому что я хочу, чтобы эти черты были расширены позже (за пределами этой кодовой базы) и заставляют эту работу просто предоставлять Карты в файле конфигурации и предоставлять объекты, которые расширяют эти черты. – bistaumanga
Даже если JVM не стирает типы, аргументы типа все равно должны быть определены во время компиляции для проверки типов. –