【问题标题】:Nested types in ScalaScala 中的嵌套类型
【发布时间】:2014-08-08 18:53:00
【问题描述】:

我有两个关于 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
}

现在我想像这样写一个通用特征(问题在模式匹配中编码为注释):

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

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

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

【问题讨论】:

    标签: scala generics types


    【解决方案1】:

    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]
    

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

    rs match {
      case List(sl1.Removed(x), sl2.Removed(y)) => (x, y)
    }
    

    模式匹配要求您明确引用嵌套实例所属的父实例。在这里,我们分别匹配sl1.Removedsl2.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 => ???
            }
        }
    }
    

    但这很尴尬,这里可能不需要嵌套类型。如果您只想将一些特征、类等组合在一个命名空间中,那么将它们放在packageobject 中,而不是traitclass。在这种情况下,您需要将类型参数 E 向下移动到 RemoveRemoved 本身:

    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
    }
    

    【讨论】:

    • 感谢您的回答。我知道您可以将这些案例类/对象放在对象/包中。事情是我正在从中派生新的实现(派生到一个对象)。
    • 我认为将值传递到另一个处理器并委托它的关注是一个非常好的主意:) 谢谢
    猜你喜欢
    • 2011-08-11
    • 2018-01-13
    • 1970-01-01
    • 2012-03-02
    • 2016-10-21
    • 1970-01-01
    • 1970-01-01
    • 2016-04-30
    • 1970-01-01
    相关资源
    最近更新 更多