在为理解创建actor时的ClassCastException

时间:2014-06-30 15:03:52

标签: scala akka scala-option self-type

我有一个演员,在这个例子中创建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("")

1 个答案:

答案 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对象。