我有一些基于Akka的演员系统,其中多种演员基于相同的模板,因为这些演员只有一种响应值不同。例如:
final case class Request(data: Any)
final case class Response(data: Any)
abstract class ActorTemplate[T] extends Actor {
def dataFunction: PartialFunction[Any, T]
def respond(data: T): Response
def receive: Receive = {
case Request(data) if dataFunction.isDefinedAt(data) =>
sender ! respond(dataFunction(data))
}
}
部分函数有一种避免类型擦除的方法,这使我无法简单地
def receive: Receive = {
case Request(data: T) =>
sender ! respond(data)
并且同时迫使我在模式上产生if dataFunction.isDefinedAt(data)
守护,我根本不喜欢它。
有没有办法避免明确的防范?
我现在唯一的方法是介绍一些愚蠢的提取器:
object DataExtractor {
def unapply(data: Any): Option[T] =
if (dataFunction.isDefinedAt(data)) Some(dataFunction(data)) else None
}
def receive: Receive = {
case Request(DataExtractor(data) =>
sender ! respond(data)
但也许它已经在标准库的某个地方完成了?或者也许有一些类似于集合collect
方法的其他方法,但是匹配?
经过一些想法后,我回到了提取器对象,并在@ pagoda_5b建议的帮助下将其移入了特征:
trait PFExtract[T] {
object PF {
def unapply(any: Any)(implicit pf: PartialFunction[Any, T]): Option[T] =
pf.lift(any)
}
}
答案 0 :(得分:3)
我实际要做的是在applyOrElse
上使用dataFunction
方法,在没有为给定输入定义部分函数时定义默认响应
def defaultAnswer: T
def receive: Receive = {
case Request(data) =>
sender ! respond(dataFunction.applyOrElse(data, defaultAnswer))
}
如果您希望将答案包裹在Option
中,那么已经有一种名为lift
的方法可以为您执行此操作,正如您正确猜到的那样
def receive: Receive = {
case Request(data) =>
sender ! respond(dataFunction.lift(data))
}
如果没有为数据
定义功能,您甚至可以决定不回答def receive: Receive = {
case Request(data) =>
dataFunction.lift(data).foreach {
sender ! respond(_)
}
}
foreach
类型上定义的 Option
仅在有一些内容可用时运行闭包内的代码(即如果您有Some(...)
)