我正在寻找一种优雅的方法来链接从公共基类型派生的部分函数。我们的想法是每个部分函数处理一个类型,因此如果链接的部分函数未定义,它们就很容易为不同的类型组合并具有共同的特征:
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}"
}
}
然后我失去了处理catch中所有未知消息的能力。是否有一些优雅的方法来实现这一目标?
答案 0 :(得分:4)
除了@adamwy + Hongxu Chen的回答,你可以定义你自己的组合器,它涉及隐式参数,因此强制执行稍微不同的应用程序语法
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)
答案 1 :(得分:3)
根据@adamwy的建议,您可以将部分功能类型更改为:
Apparent symbolic reference i not allowed.
WARNING: Apparent symbolic reference VALUE not resolved.
WARNING: Apparent symbolic reference I not resolved.
ERROR 22-322: Syntax error, expecting one of the following:
a name, a quoted string, a numeric constant,
a datetime constant, a missing value, INPUT,
PUT.