【发布时间】:2016-08-05 08:12:24
【问题描述】:
我有两个特征及其实例对象定义如下:
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
}
我想在运行时从名称中获取 monoid 实例。例如,如果我说"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]。我无法使用我想出的resolve 方法解析trait Monoid[T] 和trait ADTHelper[T] 的基础类型T。如何修改 resolve 函数,以便它解析具有基础类型 T 的特征?
我知道如果我使用resolve[Double](...) 调用,它会起作用,但我希望它在运行时从AGGREGATORS_ADT_DICT 解决。
【问题讨论】:
标签: scala generics reflection