receive
方法定义了Akka actors中的actor行为。我正在寻找一种方法,可以在Scala中以最好的方式在运行时给出所有不同的消息(及其类型),一个actor可以处理它们。
直接回答
很遗憾,你所要求的功能在akka
中不可用。 receive
方法被定义为:
type Receive = PartialFunction[Any, Unit]
abstract def receive : Actor.Receive
PartialFunction
没有办法枚举它可以处理的所有类型。此外,一旦将 Actor
实例化为 ActorRef
,您就无法访问底层的 receive
方法。
另一种选择是在 Actor
实现之外定义您的接收方法,然后使用 PartialFunction
的 isDefinedAt
方法 来测试特定值:
object MyActor {
val myPartial : Receive = {
//receive functionality
}
}
class MyActor extends Actor {
override def receive : Receive = MyActor.myPartial
}
//test if a value can be processed by MyActor
val testValue = 42
val testValueIsDefined = MyActor.myPartial.isDefinedAt(testValue)
间接回答
如果您正确地组织自己的代码,那么您的问题的基础就变得不必要了。
我发现一个好的实践是严格声明Actor可以接收哪些类型的输入:
sealed trait MyActorInputs
case class Foo(value : Int) extends MyActorInputs
case class Bar(value : String) extends MyActorInputs
object MyActor {
val processInput : MyActorInput => Unit = ???
}
class MyActor extends Actor {
override def receive : Receive = {
case input : MyActorInput =>
MyActor.processInput(input)
case unknown =>
System.error.println(s"MyActor received unknown input: $unknown")
}
}
这种技术并不提供编译时检查或严格的保证,但如果您在所有Actor中都采用它,那么对于更大的项目来说,它往往会使生活变得更加轻松。它还将允许您使用反射动态获取可用输入类型的列表。
PartialFunction[X, Y]
不保证处理任何给定的 X
。 - Levi Ramsey
receive
方法传递了一个PartialFunction[Any, Unit]
。在Akka Typed中,您必须指定可以处理的消息类型。 - eripcontext.become
,一个actor可以动态地改变其行为(如果actor没有context.become
,则receive
方法只是默认值)。 - Levi RamseyActorCell
中为behaviorStack
)。如果您可以访问该字段,您可以获取其头部以获取当前行为,这是一个PartialFunction[Any, Unit]
。从那里,您可以将消息传递给isDefinedAt
方法。最多只能让您拥有Actor此时可以处理的消息列表,这并不完全符合您的要求,但是除非存在主要的JVM漏洞,否则您无法访问该私有字段,所以这没关系。 - Levi Ramsey