Scala 向Akka中的父演员发送消息

Scala 向Akka中的父演员发送消息,scala,akka,akka-typed,Scala,Akka,Akka Typed,标题是不言自明的,我希望能够向家长参与者发送消息(意思是我希望家长的ActorRef)。在Akka Classic(非类型化)中,可以通过以下方式从孩子的ActorContext中获取家长演员的ActorRef: context.parent (例如,见) 但是,akka typed中的akka.actor.typed.scaladsl.ActorContext不会为父级公开ActorRef。在Scala中,是否有一种惯用的方法来为父角色获取一个ActorRef?如果您使用的是类型化的Akka

标题是不言自明的,我希望能够向家长参与者发送消息(意思是我希望家长的
ActorRef
)。在Akka Classic(非类型化)中,可以通过以下方式从孩子的
ActorContext
中获取家长演员的
ActorRef

context.parent
(例如,见)


但是,akka typed中的
akka.actor.typed.scaladsl.ActorContext
不会为父级公开
ActorRef
。在Scala中,是否有一种惯用的方法来为父角色获取一个
ActorRef

如果您使用的是类型化的Akka,那么可以包含所有可能的父角色的
ActorRef
的唯一[Scala]类型是
ActorRef[无]
,这是一个您无法向其发送消息的
ActorRef
,因此,这是有限的效用

至少在经典API存在的情况下:

import akka.actor.typed.scaladsl.adapter._

type ClassicActorRef = akka.actor.ActorRef

val parentActorRef = context.toClassic.parent
这将是一个非类型化的
ActorRef
,即您可以自由发送家长参与者永远不会接受的消息

如果希望对参与者的父级进行类型化引用,则在生成子参与者时需要嵌入该引用,就像希望对当前消息的发件人进行类型化引用一样,您需要在协议中嵌入
replyTo
s

context.sender
在键入的
ActorContext
中不存在,原因与
context.parent
不存在相同;复制经典
上下文的解决方法。sender
类似:
context.toClassic.sender

TLDR: 在创建父参与者引用时将其注入子参与者引用

Akka Typed强制执行严格的协议,所以您需要绝对清楚地表明“这个参与者与另一个参与者对话”。公认的答案是一种变通方法(转换为经典并使用父级),但也有其缺点:现在不再强制执行类型

下面是一些应该让您开始的代码。查看如何强制执行所有类型。你可以用不同的方式模拟这些特征,但你应该了解其中的大意:

object ParentActor {
  sealed trait Command 
  
  case class DoSomething() extends Command
  
  // you do not have to do this, but creating another trait
  // allows you to narrow the amount of messages the parent can receive from the child
  sealed trait ChildNotification extends Command
  case class MessageFromChild() extends ChildNotification

  
  def apply(): Behavior[Command] = {
    Behaviors.receive( (context, message) => 
      message match {
        case DoSomething() =>
          // create a child that knows about its parent
          context.spawn(ChildActor(context.self), "child")
          Behaviors.same

        case MessageFromChild() =>
          context.log.info("I received a message from my child")
          Behaviors.same
      })
  }
}

object ChildActor {
  sealed trait Command
  case class Work() extends Command
  
  // inject the parent here (or any other actor that matches the signature)
  def apply(parent: ActorRef[ParentActor.ChildNotification]): Behavior[Command] = {
     Behaviors.receive( (context, message) => 
       message match {
         case Work() =>
           // send message to parent actor (or any other actor with that type)
           parent ! ParentActor.MessageFromChild()
           Behaviors.same

     })
  }
}

顺便说一下,我使用的是akka类型的“函数”语法,但您也可以使用更“面向对象”的语法。它遵循相同的方法。

这是否回答了您的问题?投票决定重新开放,因为自被投票的问题被复制以来,相关API发生了巨大的变化。Akka 2.6与之前的2.6和2.6版本有很大的不同,因此答案可能很难回答。对于OP,您是否使用类型化的actor API?值得编辑您的问题,以明确这一点(2.6中的旧答案不适用于您,但只是为了明确起见),用户的原始帖子提到“许多过时的答案”不适用。因为如果不使用类型化API,那些过时的答案是有效的。(请注意,如果按照官方Akka文档中Akka Actor的链接,您可以访问类型化API的文档,即如果Akka是新手,则类型化API是Akka Actor),我还将在目标问题中针对经典和类型化问题给出一个适合Java的答案,因为这可能会更高。