对... Scala 中的内部类有点繁琐。在我向您展示您提供的代码的重写版本之前,让我们尝试一个简单的示例。
case class Foo(x: Int) {
case class Bar(y: String)
}
现在,考虑以下代码 sn-p:
val x = new Foo(1)
val y = new Foo(2)
val a = new x.Bar("one")
val b = new y.Bar("two")
a 和b 最通用的类型是Foo#Bar,这意味着内部类Bar 与Foo 类型的任何外部对象。但我们可以更具体的说a 的类型是x.Bar,b 的类型是y.Bar——这意味着a 是内部类Bar 的一个实例对象x,类似b。
您实际上可以通过调用typeOf(a) 和typeOf(b) 看到类型不同,其中typeOf 是这样定义的实用方法。 (它只是通过非常好的类型推断和Manifests 的一点使用来给出它的参数的类型)
def typeOf[T](x: T)(implicit m: scala.reflect.Manifest[T]) = m.toString
由于内部对象持有对其封闭对象的引用,您不能在不指定外部对象的情况下实例化内部对象。因此,您可以调用new x.Bar("one"),但不能调用new Foo#Bar("?") - 因为在第二种情况下,您没有指定您尝试构造的新对象的内部对象是什么。
那么,让我们回到您的代码 sn-p。当您进行模式匹配时,您实际上是在调用构造函数 - 当调用 C1(e1) 时。由于C1 是Container[TKey]#C1
的别名,您试图调用内部类的构造函数而不指定其外部对象,但由于上述原因而失败。我编写代码的方式如下:
trait Container[TKey] {
abstract trait CB
case class C1(val e : AnyRef) extends CB
case class C2(val e : AnyRef) extends CB
}
class DoStuff[TKey] (val c: Container[TKey], val element: Container[TKey]#CB) {
element match {
case c.C1(e1) => Some(e1)
case c.C2(e2) => Some(e2)
case _ => None
}
}
现在可以编译了,希望它能达到你想要的效果。但请务必小心!由于类型擦除,Scala 不能保证 element 实际上是 c.CB 类型或 d.CB 类型,而 CB 在 c 和 d 的情况下恰好是相同的。
考虑这个例子:
def matcher(arg: Foo#Bar) = {
arg match {
case x.Bar(n) => println("x");
case y.Bar(n) => println("y");
}
}
x 和 y 和以前一样。尝试运行以下命令:
matcher(a)
matcher(b)
他们都打印x!
因此我会重写代码以在容器中显式地拥有一个元素:
trait Container[TKey] {
abstract trait CB
case class C1(val e : AnyRef) extends CB
case class C2(val e : AnyRef) extends CB
val element: CB
}
class DoStuff[TKey](val c: Container[TKey]) {
c.element match {
case c.C1(e1) => Some(e1)
case c.C2(e2) => Some(e2)
case _ => None
}
}
希望对你有帮助:)
-- 弗拉维乌·西普西根