Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/hadoop/6.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Scala 2.10中具有泛型类型的特征集合_Scala_Generics_Reflection_Scala 2.10 - Fatal编程技术网

Scala 2.10中具有泛型类型的特征集合

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)来构建在运行时定义并使用类型泛型的对象集合,但我很难将它们转换回子对象。一些示例代码和结果:

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"
如果我硬编码a
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
一种解决方案是创建一个
列表[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 from
shapeless
更灵活,但您仍然无法在运行时确定任意的算术数,因此我依赖于某种类型的集合。。。再次感谢你的帮助!我相信有更好的方法来满足你的需求。如果您知道位置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