akka actor текущее имя функции приема

У меня есть простой актер с 2 поведением

package com.hello

import akka.actor.{Actor, ActorLogging}

case object Ping

class Hello extends Actor with ActorLogging {

  import context._

  def receive: Receive = behaviorFoo

  self ! Ping

  def behaviorFoo: Receive = {
    case _ =>
      log.info(this.receive.getClass.getSimpleName)
      become(behaviorBar)
      self ! Ping
  }

  def behaviorBar: Receive = {
    case _ =>
      log.info(this.receive.getClass.getSimpleName)
  }
}

эту вещь делают те:

пинг себя

регистрация текущей функции приема

изменить поведение на поведение Bar

пинг себя

регистрация текущей функции приема

в обоих случаях записывается "$ anonfun $ поведение Foo$1"

почему это не "$ anonfun $ поведение Bar$1" во втором журнале?

если я поменяю код на

  self ! Ping

  def receive: Receive = {
    case _ =>
      log.info(this.receive.getClass.getSimpleName)
      become(behaviorFoo)
      self ! Ping
  }

  def behaviorFoo: Receive = {
    case _ =>
      log.info(this.receive.getClass.getSimpleName)
      become(behaviorBar)
      self ! Ping
  }

  def behaviorBar: Receive = {
    case _ =>
      log.info(this.receive.getClass.getSimpleName)
  }

он записывает 3 раза "$ anonfun $ получает $ 1"

существует ли какой-либо способ получить текущее поведение (получить) имя функции? или мне нужно в любое время напечатать как log.info("поведение Foo")?

Обновить:

для регистрации проблем, я добавил

trait MyLogging extends ActorLogging {
  this: Actor ⇒

  private[this] val actorClassName = this.getClass.getSimpleName

  private[this] var receiveName: String = {
    val receiveClassName = s"${this.receive.getClass.getSimpleName}"
    val left = receiveClassName.substring(0, receiveClassName.lastIndexOf("$"))
    left.substring(left.lastIndexOf("$") + 1)
  }

  def become(behavior: Actor.Receive): Unit = {
    val behaviorClassName = behavior.getClass.getSimpleName
    val left = behaviorClassName.substring(0, behaviorClassName.lastIndexOf("$"))

    receiveName = left.substring(left.lastIndexOf("$") + 1)

    context.become(behavior)
  }

  def info(message: Any): Unit = log.info(s"$actorClassName : $receiveName got $message")
}

тогда мой код актера станет

class Hello extends Actor with MyLogging {

  def receive: Receive = behaviorFoo

  self ! Ping

  def behaviorFoo: Receive = {
    case any =>
      info(any)
      become(behaviorBar)
      self ! Ping
  }

  def behaviorBar: Receive = {
    case any => info(any)
  }
}

теперь логи выглядят как

... Привет

... Привет: поведение Bar получил Ping

1 ответ

Решение

Может быть, поэтому они называются анонимными функциями. behaviorFoo, behaviorBar... имена не влияют на эти анонимные функции. Чтобы проиллюстрировать это, рассмотрим это:

// this is a val!
val behaviorFoo: Receive = {
  case _ =>
    log.info(this.receive.getClass.getSimpleName)
    become(behaviorBar)
    self ! Ping
}
// this returns the same anonymous function
def behaviorFoo2 = behaviorFoo

С учетом вышесказанного вы должны увидеть, что имя, под которым вы храните анонимную функцию, не имеет ничего общего с самой анонимной функцией...

Теперь, если вы понимаете, что это за анонимные функции (это частичные функции с псевдонимом типа Actor.Receive) вы можете сделать что-то вроде ниже:

// not an anonymous function anymore
class BehaviourFoo extends Actor.Receive {
  val anonymousFun: Actor.Receive = {
    case _ =>
      log.info(this.receive.getClass.getSimpleName)
      become(behaviorBar)
      self ! Ping
  }
  override def isDefinedAt(x: Any) = anonymousFun.isDefinedAt(x)

  override def apply(x: Any) = anonymousFun(x)
}
// again, the name behaviorFoo doesn't matter
def behaviorFoo: Receive = new BehaviourFoo

Это, конечно, не стоит хлопот, но это должно помочь вам понять, что происходит.

Другие вопросы по тегам