ClassCastException при создании актера для понимания

У меня есть актер, который создает детей актеров типа Child1 в этом примере. Child1 Конструктор принимает две строки, которые извлекаются из переменных, которые находятся в SomeTrait это смешано в SomeActor isntance.

trait SuperTrait {
  lazy val str1: Option[String] = None
  lazy val str2: Option[String] = None
} 
trait SomeTrait extends SuperTrait {
  override lazy val str1: Option[String] = Some("Str1")
  override lazy val str2: Option[String] = Some("Str2")
}
class SomeActor extends Actor {
  this: SuperTrait => 
  var child: Option[ActorRef] = None
  override def preStart(): Unit = {
    child = for {
      st1 <- str1 
      st2 <- str2
    } yield context.actorOf(Child1.props(st1, st2)))
  }
}

Создание на SomeActor пример:

context.actorOf(Props[SomeActor with SomeTrait])

При этом я получаю странную ошибку:

SomeActor cannot be cast to SomeTrait,

Похоже, что извлечение переменных из контейнера параметров SomeTrait бросает это исключение.

Что мне здесь не хватает?

И это происходит не только с for comprehensions. Также, когда я пытаюсь сделать str1.getOrElse("") или добавить геттер в SomeTrait: def getStr1 = str1.getOrElse("")

1 ответ

Как сказал @ggovan выше, при использовании Akka вы не можете контролировать конструкцию Actor. Об этом позаботится библиотека Akka (и поэтому у вас есть Props для инкапсуляции параметров, передаваемых в конструктор). Причина этого в том, что если ваш актер терпит крах, его супервизор должен иметь возможность создать его новый экземпляр.

Когда вы используете реквизит [X], Scala использует ClassTag найти класс времени выполнения Actor. Тем не менее ClassTag похоже, не подбирает анонимный класс, созданный при вызове Props[X with Y], он подхватывает только базовый класс (в вашем случае, SomeActor). Обходной путь - использовать альтернативу Props по имени, так что вы можете сделать это при создании SomeActor:

val actor = sys.actorOf(Props(new SomeActor with SomeTrait))

Это работает, и это поднимает переопределенные ленивые vals также. Обязательно ознакомьтесь с минусами этого на http://doc.akka.io/docs/akka/snapshot/scala/actors.html (раздел "Опасные варианты").

Другой вариант - использовать Cake Pattern:

trait SomeTrait {
  lazy val str1: Option[String] = None
  lazy val str2: Option[String] = None
}

trait ActorTrait extends Actor {
  this: SomeTrait => 
  override lazy val str1 = Some("Str1")
  override lazy val str2 = Some("Str2")
  var child: Option[ActorRef] = None
  override def preStart(): Unit = {
    child = for {
      st1 <- str1 
      st2 <- str2
    } yield context.actorOf(Child1.props(st1, st2)))
  }
}

class SomeActor extends ActorTrait with SomeTrait

В этом случае вы можете использовать рекомендуемые Props[SomeActor] метод для создания объекта Props.

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