4

如何使用与别名类型匹配的案例类?这在我将 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
}

谢谢!

4

1 回答 1

8

对... 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") 

aand最通用的类​​型bFoo#Bar,表示内部类Bar具有任何类型的外部对象Foo。但是我们可以更具体的说 is 的类型和isax.Bar类型——这意味着它是带有外部对象的内部类的实例,类似于.by.BaraBarxb

typeOf(a)您实际上可以通过调用and看到类型不同typeOf(b),其中typeOf定义了一个实用方法。(它只是通过非常好的类型推断和对Manifests 的一点使用给出了它的参数的类型)

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 不能保证element是实际类型c.CB或类型d.CBCB在这种情况下cd碰巧是相同的。

考虑这个例子:

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

希望能帮助到你 :)

——弗拉维乌·西普西根

于 2009-11-28T19:32:27.013 回答