如何使用与别名类型匹配的案例类?当我从容器中取出CB等时,这就有效。

class DoStuff[TKey](
  val c : Container[TKey]#CB
)
{
  type CB = Container[TKey]#CB
  type C1 = Container[TKey]#C1
  type C2 = Container[TKey]#C2

  c match {
    case C1(e1) => e1  //   - not found: value e1   - not found: value C1
    case C2(e2) => e2 //    - not found: value e2   - not found: value C2
  }
}

trait Container[TKey]
{
    abstract trait CB
    case class C1(val e : AnyRef) extends CB
    case class C2(val e : AnyRef) extends CB
}

谢谢!

有帮助吗?

解决方案

正确... Scala中的内部类有点繁琐。在我向您展示您提供的代码的重写版本之前,让我们尝试一个简单的示例。

case class Foo(x: Int) {
  case class Bar(y: String) 
}

现在,请考虑以下代码段:

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 是一个实用程序这样定义的方法。 (它只是通过非常好的类型推断给出了它的参数类型,并且使用了 Manifest

def typeOf[T](x: T)(implicit m: scala.reflect.Manifest[T]) = m.toString

当内部对象保存对其封闭对象的引用时,不能实例化内部对象而不以某种方式指定其外部对象。因此,您可以调用 new x.Bar(“one”)但不能调用 new Foo#Bar(“?”) - 与第二种情况一样你没有指定你试图构造的新对象的内部对象是什么。

所以,让我们回到你的代码片段。当你进行模式匹配时,实际上是在调用 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无法保证元素实际上是 c.CB 类型或类型 d.CB 所在的 c d 的情况下,CB 恰好相同。

考虑这个例子:

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
  }
}

希望有所帮助:)

- Flaviu Cipcigan

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top