我试图通过引用他们的超类(好,特性)来构建在运行时定义并使用类型泛型的对象集合,但是我很难将它们转换回到儿童对象。一些示例代码和结果:
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
)一个对象回到错误的类型,但我似乎无法得到它工作。提前谢谢!
答案 0 :(得分:0)
我不确定您要做什么,但您遇到的问题是因为myTraitList
的类型与List[MyTrait[Any]]
类似。由于类型为_
,编译器不知道它是Bar
还是Foo
。值得庆幸的是,Scala提供了模式匹配,允许您对对象的类型进行条件。
def conditionalDo(x: MyTrait[_]) = {
x match {
case i: Foo => println("doing foo() stuff")
case j: Bar => println("doing bar() stuff")
case _ => println("error!")
}
}
myTraitList.foreach(conditionalDo)
trait MyTrait {
def f(x: Any): Int
}
class Foo extends MyTrait {
def f(x: Any) = {
x match {
case i: Int => 1
case _ => -1
}
}
}
class Bar extends MyTrait {
def f(x: Any) = {
x match {
case j: String => 2
case _ => -1
}
}
}
val fooInstance: Foo = new Foo
val barInstance: Bar = new Bar
val myTraitList: List[MyTrait] = List(fooInstance, barInstance)
myTraitList(0).f(1) // returns 1
myTraitList(1).f("s") // returns 2