Scala隐式类具有异构的子类型列表

时间:2016-04-19 23:35:42

标签: scala

我通过接口描述语言在外部定义并生成了几个Event类。这些类型的定义超出了我的控制范围 - 我只能访问简单生成的案例类:

sealed trait Event
case class EventOpen(msg: String) extends Event
case class EventClose(msg: String) extends Event

鉴于这些事件的列表,我需要将它们折叠成单个值。目的是建立一个折叠函数库,可以根据需要为给定的上下文使用。例如,确定流是打开还是关闭。为了避免折叠函数内部的巨大模式匹配,因为事件列表很长,我希望使用隐式类,根据需要为每个事件添加功能,并根据需要打包导入:< / p>

sealed trait Status
case object Open extends Status
case object Closed extends Status
case object Unknown extends Status

// Do nothing unless a specific EventOp is defined.
implicit class EventNoOp(event: Event) {
  def accumulate(status: Status): Status = status
}

implicit class EventOpenOp(event: EventOpen) {
  def accumulate(status: Status): Status = Open
}

implicit class EventCloseOp(event: EventClose) {
  def accumulate(status: Status): Status = Closed
}

val initial: Status = Unknown
List(EventOpen("yeeha"), EventClose("adios")).foldLeft(initial)((status, event) => event.accumulate(status))  // => Unknown

问题是特定类型的事件在折叠中丢失,因此只调用EventNoOp,导致“未知”而不是“已关闭”。折叠函数内部的明确模式匹配解决了这个问题,但这首先违背了该方法的目的:

val initial: Status = Unknown
List(EventOpen("yeeha"), EventClose("adios")).foldLeft(initial)((status, event) => {
  event match {
    case e: EventOpen => e.accumulate(status)
    case e: EventClose => e.accumulate(status)
  }
})

有没有办法避免每个事件的显式模式匹配?

1 个答案:

答案 0 :(得分:4)

  

有没有办法避免每个事件的显式模式匹配?

我认为使用implicits的解决方案实际上导致更多样板文件比使用模式匹配...这对我来说比基于隐式的解决方案更直观:

def accumulateStatus(status: Status, event: Event): Status = event match {
  case EventOpen(_)  => Open
  case EventClose(_) => Closed
  case _             => status
}

val initial: Status = Unknown
List(EventOpen("yeeha"), EventClose("adios")).foldLeft(initial)(accumulateStatus) 

由于你不能直接修改Event类,你将会遇到模式匹配(或者使用运行时类型比较/反射做一些更尴尬的事情)。