Scala 如何将参与者消息限制为特定类型?

Scala 如何将参与者消息限制为特定类型?,scala,actor,akka,Scala,Actor,Akka,在中,除了使用使用RPC风格编程模型的“类型化的参与者”API外,是否有其他方法将发送给参与者的消息限制为特定的静态类型 我可以在Akka中使用消息传递样式,而不在参与者边界上丢弃静态类型的安全性吗 例如,我想使用如下代码: sealed abstract class FooMessage case object Foo extends FooMessage case object Bar extends FooMessage class FooActor extends Actor[FooM

在中,除了使用使用RPC风格编程模型的“类型化的参与者”API外,是否有其他方法将发送给参与者的消息限制为特定的静态类型

我可以在Akka中使用消息传递样式,而不在参与者边界上丢弃静态类型的安全性吗

例如,我想使用如下代码:

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"
也许你必须扩展一些基本特征,或者使用类似于
的结构来允许系统级消息(
Exit
,等等)。

在Scala stdlib中,基本角色是非类型化的(这不适用于Akka,因为我记得它不支持嵌套接收)。反过来,Lift支持输入的演员跳出盒子

但是,使用通道,仍然可以使用stdlib创建强类型参与者:

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;

}

然后,您必须将消息类型编码到Actor ref中,这将大大降低ActorRegistry之类的值

此外,使用强大的机制,如“变成”(这是参与者模型的基础),键入消息的价值也会降低

由于Akka不会在消息与当前行为不匹配时泄漏内存,因此向“错误”参与者发送“错误”消息的风险也不相同

此外,参与者本质上是动态的,所以如果您想使它们成为静态的,请使用TypedActor(它不是RPC,它与常规参与者一样是RPC,void方法是!调用,未来返回类型是!!!其他返回类型基于!!)

通常的做法是在参与者的同伴对象中声明参与者可以接收哪些消息,这使得了解参与者可以接收哪些消息变得非常容易


这有帮助吗?

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

有一种方法用于参与者()的严格类型化输入:

在您的情况下,接口由单个输入触点组成:

val FooInput = contact[FooMessage]("FooInput")
在SynapseGrid框架内,信号处理由Builder定义:

class FooActorBuilder extends SystemBuilder {
  inputs(FooInput, OtherInput)
  FooInput.foreach(fooMessage => () //OK
  )
  OtherInput.foreach(...)
}
显然,不能用不兼容的类型构造信号。因此,我们有编译时检查。在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
听起来阿克卡应该解决这个问题,但是(根据)

在Akka 2.2.3的文档中,有一个很好的章节讨论了支持类型化消息发送和响应的困难


罗兰·库恩(Roland Kuhn)在《Akka类型化频道:将类型计算实现为宏》(/)上的一篇很好的NEScala演讲》中讨论了类型化频道的实现。

感谢您提供了有用的答案。您(akka团队)是否曾经尝试过向参与者的消息添加类型约束,或者这从来没有被认为是一个有用的想法?在过去的列表中已经有关于它的讨论,但我们总是在同一个地方结束,TypedActor用于那个用例,而参与者用于整个动态行为。如果你想感觉自己更能掌控局面,你可以在ActorRef上尝试你自己的抽象。这有用吗?干杯√类型化频道已被删除。“类型化通道是我们决定删除的一项实验性功能:它的实现依赖于Scala的一项实验性功能,Java和其他语言对此没有对应关系,而且它的使用也不直观。”
val inputMessage = Signal(FooInput, Foo)
actor ! inputMessage