2016-12-07 51 views
1

我正在寻找一种优雅的方式来链接从一个共同的基础类型派生的部分功能。这个想法是,每个部分函数处理类型,使他们成为很容易的出现了不同类型和有一个共同的包罗万象的,如果链接的部分功能是不确定的:链接斯卡拉部分功能的优雅方式

trait Message 
trait SysMessage extends Message 
trait UserMessage extends Message 

case class TextSysMessage(m: String) extends SysMessage 
case class TextUserMessage(m: String) extends UserMessage 

class Test { 

    type MessagePF = scala.PartialFunction[Message, String] 
    type SysMessagePF = scala.PartialFunction[SysMessage, String] 
    type UserMessagePF = scala.PartialFunction[UserMessage, String] 

    def getSysMessage: SysMessagePF = { 
    case sm: TextSysMessage ⇒ s"System message: ${sm.m}" 
    } 

    def getUserMessage: UserMessagePF = { 
    case um: TextUserMessage ⇒ s"User message: ${um.m}" 
    } 

    def * : MessagePF = { 
    case m ⇒ s"Unknown message: $m" 
    } 

    // Chained partials fails because `m` is a SysMessage with UserMessage 
    def handler(m: Message): String = (getSysMessage orElse getUserMessage orElse *)(m) 
} 

显然,这种方法并不能编译。我可以通过这样的嵌套模式匹配来解决这个问题

def getSysMessage: MessagePF = { 
    case m: SysMessage ⇒ m match { 
    case sm: TextSysMessage ⇒ s"System message: ${sm.m}" 
    } 
} 

但是然后我失去了处理未知消息的能力。有没有一些优雅的方式来实现这一目标?

+4

为什么不用'Message'作为输入类型定义每个'PartialFunction'? – adamwy

+0

这基本上是计划B .... –

+0

但你怎么能期望一个部分函数,​​需要具体的子类型与任意'消息'工作?类似于'def handler(m:Message):String =(getSysMessage)(m)'也不起作用。 – adamwy

回答

2

至于除了@adamwy +杨红旭陈的回答,您可以定义自己的组合子,它涉及隐含参数,所以强制执行略有不同的应用程序的语法

implicit class PartFuncOps[A: ClassTag, B](pf: PartialFunction[A, B]) { 
    def or[D >: A, C <: D : ClassTag](other: PartialFunction[C, B]): PartialFunction[D, B] = { 
    case a: A if pf.isDefinedAt(a) ⇒ pf(a) 
    case c: C if other.isDefinedAt(c) ⇒ other(c) 
    } 
} 

现在你可以写

def combine = getSysMessage or getUserMessage or * 
def handler(m: Message): String = combine(m) 

def handler(m: Message): String = (getSysMessage or getUserMessage or *).apply(m) 
3

正如@adamwy建议,您可以更改部分功能类型为:

type MessagePF = scala.PartialFunction[Message, String] 
type SysMessagePF = scala.PartialFunction[Message, String] 
type UserMessagePF = scala.PartialFunction[Message, String] 
+1

或者只是使用一种类型。 – adamwy