我有一个演员,在这个例子中创建Child1
类型的儿童演员。 Child1
构造函数接受两个 String ,这些 String 是从驻留在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
上。此外,当我尝试str1.getOrElse("")
或向SomeTrait
添加吸气剂时:def getStr1 = str1.getOrElse("")
答案 0 :(得分:3)
正如@ggovan上面所说,当使用Akka时,你无法控制一个Actor的构造。 Akka库负责处理(这就是为什么你有Props来封装传递给构造函数的参数)。原因是,如果你的演员崩溃,其主管需要能够创建它的新实例。
当您使用Props [X]时,Scala使用a ClassTag
来查找Actor的运行时类。但是,ClassTag
似乎没有选择在您调用Props[X with Y]
时创建的匿名类,它只选择基类(在您的情况下为SomeActor
)。解决这个问题的方法是使用Props的by-name替代方法,这样你就可以在创建SomeActor时执行此操作:
val actor = sys.actorOf(Props(new SomeActor with SomeTrait))
这样可行并且它也会获取被覆盖的懒惰值。但是,请务必阅读http://doc.akka.io/docs/akka/snapshot/scala/actors.html处的缺点(“危险变体”部分)。
另一种选择是使用蛋糕模式:
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对象。