Scala 中的嵌套类型

mar*_*_dj 1 generics types scala

我有两个关于 Scala 中嵌套类型的问题。

想象一下我有这种特质;

trait ScanList[E] {
  sealed trait Command
  case object Recover extends Command
  case class Remove(item: E) extends Command

  sealed trait Event
  case class Removed(item: E) extends Event
}
Run Code Online (Sandbox Code Playgroud)

现在我想写一个通用特征,如下所示(问题在模式匹配中编码为注释):

trait ScanListProcessor[E] {
    type SL = ScanList[E]

    def process(msg: SL#Command) = {
        msg match {
            case u:SL#Remove => // how can instantiate SL#Removed here?
            case SL#Recover => //cannot match on nested objects?
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

使用特征的原因是我可以派生 ScanList 的新实现。在这个特质中,我也有类似的操作def shouldProcess(item: E): Boolean。对于每个实现,ScanList[E]我想编写如上所述的通用行为。

  1. 如何在泛型类型中的嵌套对象上进行模式匹配?
  2. 是否可以从类型构造函数实例化?例如:SL#Removed?我想拥有一个通用参数并尝试从中构造一个值是一样的,类型类可以解决这个问题吗?

win*_*ner 5

Scala 中的嵌套特征、类和对象就像 Java 中的内部类一样。您创建的它们的任何实例都与创建它们的父类/特征的实例相关联。所以从你的例子继续:

val sl1 = new ScanList[Int] {}
val sl2 = new ScanList[Int] {}
val r1 = sl1.Removed(1) // has type sl1.Removed
val r2 = sl2.Removed(2) // has type sl2.Removed
val rs = List(r1, r2) // has type List[ScanList[Int]#Removed]
Run Code Online (Sandbox Code Playgroud)

您可以对它们进行模式匹配,例如:

rs match {
  case List(sl1.Removed(x), sl2.Removed(y)) => (x, y)
}
Run Code Online (Sandbox Code Playgroud)

模式匹配要求您显式引用嵌套实例所属的父实例。这里,我们分别对sl1.Removed和进行匹配sl2.Removed

至于第二个问题,SL#Removed如果没有可用的父实例,则无法创建。有了一个,就这么简单sl1.Removed(1)

ScanListProcessor可以重写以将ScanList其操作作为值:

class ScanListProcessor[E](val sl: ScanList[E]) {
    def process(msg: sl.Command) = {
        msg match {
            case sl.Remove(x) => sl.Removed(x)
            case sl.Recover => ???
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

但这很尴尬,而且这里可能不需要嵌套类型。如果您想要做的只是将一些特征、类等分组到一个命名空间中,那么请将它们放在 a packageorobject而不是 a traitor中class。在这种情况下,您需要将类型参数E向下移动到Remove它们Removed本身:

object ScanList {
  sealed trait Command
  case object Recover extends Command
  case class Remove[E](item: E) extends Command

  sealed trait Event
  case class Removed[E](item: E) extends Event
}
Run Code Online (Sandbox Code Playgroud)