2016-04-19 108 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類,就會陷入模式匹配的困境(或者在運行時類型比較/反射方面做得更加尷尬)。