【发布时间】:2015-06-18 23:25:07
【问题描述】:
我正在尝试通过引用它们的超类(好吧,特征)来构建在运行时定义并使用类型泛型的对象集合,但是我很难将它们转换回子对象。一些示例代码和结果:
trait MyTrait[T] {
def f(x: T): Int
}
class Foo extends MyTrait[Double] {
def f(x: Double) = 1
}
class Bar extends MyTrait[String] {
def f(x: String) = 2
}
val fooInstance: Foo = new Foo
val barInstance: Bar = new Bar
val myTraitList: List[MyTrait[_]] = List(fooInstance, barInstance)
println(fooInstance.getClass)
// prints "class MyExample$Foo"
println(barInstance.getClass)
// prints "class MyExample$Bar"
println(myTraitList(0).getClass)
// prints "class MyExample$Foo", so the list is preserving object classes and not just "MyTrait[_]"
println(myTraitList(1).getClass)
// prints "class MyExample$Bar", again, preserving object class
println(fooInstance.f(1.0))
// prints "1"
println(barInstance.f("blah"))
// prints "2"
println(myTraitList(0).f(1.0))
// this is where things break:
// "type mismatch; found : Double(1.0) required: _$3 where type _$3"
// so, the list element knows it's an instance of Foo (as indicated by getClass), but has lost the overloaded definition of f
println(myTraitList(1).f("blah"))
// the same error occurs on the Bar instance:
// "type mismatch; found : String("blah") required: _$3 where type _$3"
如果我硬编码myTraitList(0).asInstanceOf[Foo].f(1.0),它(可以预见地)工作得很好。因此,我尝试创建一个函数来在运行时执行此操作:
def castToCorrectChildClass(o: MyTrait[_], label: Char): MyTrait[_] = {
return label match {
case 'f' => o.asInstanceOf[Foo]
case 'b' => o.asInstanceOf[Bar]
case _ => o
}
}
不幸的是,这会遇到同样的问题:
println(castToCorrectChildClass(myTraitList(0), 'f').f(1.0))
// type mismatch; found : Double(1.0) required: _$2 where type _$2
一种解决方案是创建一个List[MyTrait[Any]] 来存储实例并使类型参数协变:trait MyTrait[+T]。不幸的是,在我的实际代码中,由于其他原因,我需要它保持不变,所以我不能使用这种解决方法。我也尝试使用 ClassTags 和 TypeTags 来记住子类认为这是一个与反射相关的问题,但我没有运气(而且我怀疑这不是这些的预期用例,尽管也许我我错了)。
有什么建议吗?我希望有一个灵活的未知数量的集合(所以,没有Tuples)的子对象扩展相同的特征,但根据运行时收集的用户输入具有不同的类型,我很高兴接受交易 -不做簿记以确保我不会将对象错误地转换(或错误-asInstanceOf)回不正确的类型,但我似乎无法让它工作。提前致谢!
【问题讨论】:
标签: scala generics reflection scala-2.10