Scala 2.10中具有泛型类型的特征集合
我试图通过引用它们的超类(trait)来构建在运行时定义并使用类型泛型的对象集合,但我很难将它们转换回子对象。一些示例代码和结果:Scala 2.10中具有泛型类型的特征集合,scala,generics,reflection,scala-2.10,Scala,Generics,Reflection,Scala 2.10,我试图通过引用它们的超类(trait)来构建在运行时定义并使用类型泛型的对象集合,但我很难将它们转换回子对象。一些示例代码和结果: 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: Fo
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"
如果我硬编码amyTraitList(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
一种解决方案是创建一个列表[MyTrait[Any]]
来存储实例并使类型参数协变:trait MyTrait[+T]
。不幸的是,在我的真实代码中,出于其他原因,我需要它保持不变,所以我不能使用这种变通方法。我还尝试使用ClassTags和TypeTags来记住子类,认为这是一个与反射相关的问题,但我没有任何运气(我怀疑这不是这些问题的预期用途,尽管我可能弄错了)
有什么建议吗?我希望有一个灵活的子对象未知数集合(因此,没有元组),扩展相同的特性,但根据运行时收集的用户输入使用不同的类型。我很乐意接受记账的折衷,以确保我不会错误地转换(或错误地将
转换为)一个对象返回到错误的类型,但我似乎无法让它工作。提前谢谢 我不确定您想做什么,但您面临的问题是,您的myTraitList
的类型类似于拥有一个列表[MyTrait[Any]]
。由于类型是。
,编译器不知道它是Bar
还是Foo
。谢天谢地,Scala提供了模式匹配,允许您对对象的类型设置条件
解决方案1
解决方案2
我不确定您想做什么,但您面临的问题是,您的myTraitList
的类型类似于拥有一个列表[MyTrait[Any]]
。由于类型是。
,编译器不知道它是Bar
还是Foo
。谢天谢地,Scala提供了模式匹配,允许您对对象的类型设置条件
解决方案1
解决方案2
谢谢marios,但是问题是我需要硬编码我想要在模式匹配代码中执行的操作。基本上,我希望在运行时从列表中检索一个对象,并将其强制转换为适当的类(例如,Foo
,或Bar
),这样我就可以在其上执行其他任意代码(如Foo.f()
或其他方法)。我不希望有一个模式匹配专门用于执行f()
,一个用于f2()
,或者MyTrait
中存在的任何其他方法,我认为这就是conditionalDo
解决方案所指向的。我遗漏了什么吗?集合是围绕单个类型抽象的(例如,List[Int]
)。如果集合的类型不同,则更通用的分母需要是类的类型。在您的例子中,是一个列表[MyTrait[\u]]
。如果您需要一个能够记住每个元素类型的集合,那么Scala可以使用Tubles来实现这一点<代码>val myTraitCollection=(fooInstance,barInstance)
。然后,您可以将其作为myTraitCollection.\u 1和myTraitCollection.\u 2进行访问,并保留所有类型信息。如果这是您想要做的,我可以将其添加到答案中。是的,确切地说,我想要一个具有不同类型但共享的特征的集合。例如,任何类型的MyTrait
s的列表。当我试图检索此列表的一个元素并将其转换回其原始(子)类(如Foo
或Bar
)时,就会出现问题<代码>元组对我来说不起作用,因为它们的算术必须在编译时知道HList
s fromshapeless
更灵活,但您仍然无法在运行时确定任意的算术数,因此我依赖于某种类型的集合。。。再次感谢你的帮助!我相信有更好的方法来满足你的需求。如果您知道位置1处的元素是Foo,位置2处的元素是Bar,那么为什么不使用Tuble呢?如果你想要一个任意长的列表,你怎么知道位置234上的元素是Foo()类型的呢?您可以使用模式匹配,也可以使用具有相同输入类型的基本方法,每个超类的实现方式不同。感谢您的持续帮助,marios。如果我在编译时知道算术,元组将是一个很好的解决方案。我想解析用户输入,并根据该输入动态创建对象列表(长度仅在运行时已知)。您的第二个解决方案更接近,但省略了类型泛型(我怀疑这可能与此问题的难度有关)。我忍不住觉得我要做的是基本的面向对象:我有一个父类的子类,我想将它们存储在一个列表中,并通过反射来识别它们的类。事实上,getClass
工作正常,但不是f
。谢谢marios,但问题是我需要硬编码操作,以便在模式匹配代码中执行对象。基本上,我希望在运行时从列表中检索一个对象,并将其强制转换为适当的类(例如,Foo
,或Bar
),这样我就可以在其上执行其他任意代码(如Foo.f()
或其他方法)。我不希望有一个模式匹配专门用于执行f()
,一个用于f2()
,或者MyTrait
中存在的任何其他方法,我认为这就是conditionalDo
解决方案所指向的。我遗漏了什么吗?集合是围绕单个类型抽象的
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