在Scala中调用Akka Actors的方法

10

我有一个被定义如下的演员:

class nodeActor(ID: String) extends Actor

这个方法被用来在演员开始前设置演员:

def addRef(actor:ActorRef)

我这样实例化这个演员:

val node1 = system.actorOf(Props(new nodeActor("node1")), name="node1")

该方法将返回一个ActorRef。由于ActorRef是子类型的成员,编译器不允许我在ActorRef上调用"addRef"。因此,我使用以下方式转换节点:

node1.asInstanceOf[nodeActor].addRef(link1)

这可以让编译器保持良好的状态。然后在运行时,我得到:

java.lang.ClassCastException: akka.actor.LocalActorRef cannot be cast to ActorStressTest.nodeActor

对我来说,这甚至似乎毫无意义,因为它是一个子类型,我应该能够将其转换为它。

有什么想法吗?


2
请通过发送消息与演员进行通信,而不是直接调用方法。那些实现演员的人努力将真正的演员实例隐藏在ActorReferences后面。这是一种不同的编程模型,请适应它。 - xiefei
1
嗨@Alex,我衷心建议你在继续之前仔细阅读文档。这可能会帮助你避免许多陷阱和很多无意义的工作。真诚地。 - pagoda_5b
“这是一个子类型..我应该能够将其转换” - 这甚至不是真的:node1 是一个 ActorRef,它像指向实际 Actor 实例的指针。你的 nodeActor 实例被隐藏在 Akka 系统中,不应直接与之交互。 - Dylan
@Dylan 好的,这似乎是我的问题所在。我以为一个 ActorRef,因为它是由构造函数类型返回的,是实际的 actor 对象,而不仅仅是指向系统的指针。现在有意义了,谢谢。 - Alex
@pagoda_5b 在发帖之前,我花了几个小时阅读akka文档。正如dylan所指出的那样,我的问题是对一个概念错误的心理模型,这通常不会因为大量阅读文档而得到解决。 - Alex
显示剩余2条评论
3个回答

7
如果您想进行测试,那么在创建演员时,只需要这样做:
import akka.testkit.TestActorRef
val actorRef = TestActorRef[MyActor]
val actor = actorRef.underlyingActor

然后您可以在演员上运行方法。

对我来说非常有帮助的答案。 :) +1 - erip

6
您不应该直接从另一个类中调用演员的方法。这会破坏整个系统的设计,其目的是:
  • 通过仅使用调用actorOfactorFor得到的ActorRef与演员的特定实现进行通信来封装演员的具体实现
  • 限制演员之间的通信,使用可用的(!?)方法进行消息传递
如果您需要在ActorA中创建对另一个ActorB的引用,您可以: 如果您需要调用一个方法以满足接口/特质约束,请查看Typed Actors

2
谢谢你的回答。我会重构我的代码以便记住这一点。我知道应该使用消息传递,但我不知道你不能使用方法调用来设置事物。无论如何,再次感谢,我接受了你的答案。 - Alex

1

您可以将任何东西转换为任何东西,编译器会愉快地这样做,但如果不可能,则运行时检查将失败。 ActorRef 不是您的 Actor 类的实例或其子类型。

当您执行此操作时:

system.actorOf(Props(new nodeActor("node1")), name="node1")

您将获得一个ActorRef,您只应该向其发送消息。除此之外,在调用system.actorOf时,该actor会立即启动,因此在启动之前尝试在Actor实例上调用方法是不可能的。

这里有一个来自Akka文档的描述,解释了actor引用。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接