2

我有一些基于 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)
 }
}
4

1 回答 1

3

我实际上要做的是使用applyOrElseon 方法dataFunction,当未为给定输入定义部分函数时定义默认响应

def defaultAnswer: T

def receive: Receive = {
  case Request(data) =>
    sender ! respond(dataFunction.applyOrElse(data, defaultAnswer))
}

如果您更喜欢将答案包装在 a 中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(_)
    }
}

foreachOption当有一些内容可用时(即,如果你Some(...)

于 2013-04-03T13:50:44.600 回答