如何将actor消息限制为特定类型?

时间:2011-04-05 06:15:21

标签: scala actor akka

Akka中,除了使用使用RPC样式编程模型的“Typed Actor”API之外,有没有办法将actor的消息限制为特定的静态类型?

我是否可以使用Akka的消息传递样式而不会在actor边界处丢弃静态类型安全性?

例如,我想使用这样的代码:

sealed abstract class FooMessage
case object Foo extends FooMessage
case object Bar extends FooMessage

class FooActor extends Actor[FooMessage] {
  def receive = {
    case Foo => () // OK

    // Would raise a compiler error:
    // case s: String => error("Can't happen, String is not a subtype of FooMessage") 

  }
}

val fooActor = actorOf[FooActor]
fooActor ! Foo // OK

// Won't compile:
fooActor ! "Hello"

也许人们必须扩展一些基本特征或者拥有像Either这样的结构来允许系统级消息(Exit等)。

4 个答案:

答案 0 :(得分:27)

然后你必须将消息类型编码到Actor ref中,这会大大降低像ActorRegistry这样的值。

此外,通过强大的机制,如“成为”(这是演员模型的基础),输入消息的价值较低。

由于当消息与当前行为不匹配时,Akka不会泄漏内存,因此将“错误”消息发送给“错误”的玩家的风险也不一样。

另外,Actors本质上是动态的,所以如果你想让它们变成静态的,那就使用TypedActor(它不是RPC,它就像RPC一样是常规actor,void方法是!调用,Future返回类型是!!!其他返回类型基于!!)

通常的做法是声明Actor可以在Actor的伴随对象中接收哪些消息,这样可以更容易地知道它可以接收的内容。

这有帮助吗?

答案 1 :(得分:23)

在Scala stdlib中有an excuse用于使基本actor无类型化(这不适用于Akka,因为它不支持嵌套接收,我记得)。反过来,提升支持开箱即用的打字演员。

但是,使用频道,仍然可以使用stdlib:

创建强类型的actor
object TypedActor {

  def apply[A](fun: PartialFunction[A, Any]): OutputChannel[A] = {
    val sink = new SyncVar[Channel[A]]
    actor {
      val in = new Channel[A](self)
      sink set in
      loop {
        in react { case any => reply(fun(any)) }
      }
    }
    sink.get
  }

}

sealed abstract class FooMessage
case object Foo extends FooMessage
case object Bar extends FooMessage

object Test {

  val fooActor = TypedActor[FooMessage]{
    case Foo => println("OK")
  }

  fooActor ! Foo 
  fooActor ! "Hello!" // doesn't compile -> Type mismatch; found: String("Hello!"); required: FooMessage;

}

答案 2 :(得分:2)

实际上,限制Actor只有一个类型作为输入并不是很有用。对我来说更有用的是以严格打字的方式列出可能的输入。

有一种方法可以严格键入演员的输入(SynapseGrid):

case class Contact[T](...)
case class Signal[T](contact:Contact[T], data:T)

在您的情况下,界面由单个输入联系人组成:

val FooInput = contact[FooMessage]("FooInput")

在SynapseGrid框架内,使用Builder定义信号处理:

class FooActorBuilder extends SystemBuilder {
  inputs(FooInput, OtherInput)
  FooInput.foreach(fooMessage => () //OK
  )
  OtherInput.foreach(...)
}

显然,不能用不兼容的类型构造Signal。因此我们有编译时检查。在SynapseGrid中,有一个用于处理信号和联系人的DSL。例如,从外面发送Foo或Bar:

val SomeOtherContact = contact[Boolean]("SomeOtherContact")
SomeOtherContact.map(flag => if(flag) Foo else Bar) >> FooInput

当然,人们可以简单地发送消息:

val inputMessage = Signal(FooInput, Foo)
actor ! inputMessage

答案 3 :(得分:1)

听起来像Akka的Akka's Typed Channel support已经解决了这个问题,但是(根据the comment has already been removed from Akka in version 2.3)。

在Akka 2.2.3的文档中,有一个很好的"design background"部分讨论了支持类型化消息发送和响应的困难。

Roland Kuhn还有一个很好的NEScala演讲, Akka类型频道:将类型计算实现为宏[YouTube] / [Slides]),讨论了实施类型化渠道。

相关问题