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 comprehension
s. Также, когда я пытаюсь сделать 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.