2016-04-19 110 views
1

我有几个事件类定义和外部由接口描述语言生成。这些类型的定义是超出了我的控制 - 我只获得了简单的生成case类:斯卡拉隐式类与异类的子类型列表

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

鉴于这些事件的列表,我需要把它们折叠成一个单一的价值。目的是构建一个折叠函数库,可以根据需要为特定的上下文使用。例如,确定一个流是打开还是关闭。为了避免折叠函数中的巨大模式匹配,因为事件列表相当长,我希望能够使用隐式类来根据需要为每个事件添加功能,并根据需要打包它们以导入:

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

有什么办法,以避免对每一个事件一个明确的模式匹配?

回答

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类,就会陷入模式匹配的困境(或者在运行时类型比较/反射方面做得更加尴尬)。