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が、マッチングのためですか?

結論

いくつかの考えの後、extractor オブジェクトに戻り、@ 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

私が実際に行うことは、applyOrElseメソッド onを使用して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(...)) 、クロージャ内でコードを実行します。

于 2013-04-03T13:50:44.600 に答える