考虑以下两个特征:
trait Poked extends Actor {
override def receive = {
case Poke(port, x) => ReceivePoke(port, x)
}
def ReceivePoke(port: String, x: Any)
}
trait Peeked extends Actor {
override def receive = {
case Peek(port) => ReceivePeek(port)
}
def ReceivePeek(port: String)
}
现在考虑我可以创建一个实现两个特征的新Actor:
val peekedpoked = actorRef(new Actor extends Poked with Peeked)
如何撰写接收处理程序?即,接收器应该是类似下面的代码,虽然“自动生成”(即所有特征应该组成):
def receive = (Poked.receive: Receive) orElse (Peeked.receive: Receive) orElse ...
答案 0 :(得分:28)
您可以使用super[T]
来引用特定超类/特征的成员。
例如:
trait IntActor extends Actor {
def receive = {
case i: Int => println("Int!")
}
}
trait StringActor extends Actor {
def receive = {
case s: String => println("String!")
}
}
class IntOrString extends Actor with IntActor with StringActor {
override def receive = super[IntActor].receive orElse super[StringActor].receive
}
val a = actorOf[IntOrString].start
a ! 5 //prints Int!
a ! "Hello" //prints String!
修改强>
回应Hugo的评论,这里有一个解决方案,允许您编写mixins,而无需手动将其接收连接在一起。本质上它涉及一个带有可变List[Receive]
的基本特征,每个混合特征都调用一个方法将自己的接收添加到列表中。
trait ComposableActor extends Actor {
private var receives: List[Receive] = List()
protected def registerReceive(receive: Receive) {
receives = receive :: receives
}
def receive = receives reduce {_ orElse _}
}
trait IntActor extends ComposableActor {
registerReceive {
case i: Int => println("Int!")
}
}
trait StringActor extends ComposableActor {
registerReceive {
case s: String => println("String!")
}
}
val a = actorOf(new ComposableActor with IntActor with StringActor).start
a ! 5 //prints Int!
a ! "test" //prints String!
要记住的唯一事情是接收的顺序不应该很重要,因为你不能轻易地预测链中的哪个是第一个,尽管你可以通过使用可变的hashmap来解决这个问题。而不是列表。
答案 1 :(得分:5)
您可以在基本actor类中使用空Receive,并在其定义中使用chain receive。 Akka 2.0-M2样品:
import akka.actor.Actor
import akka.actor.Props
import akka.event.Logging
import akka.actor.ActorSystem
class Logger extends Actor {
val log = Logging(context.system, this)
override def receive = new Receive {
def apply(any: Any) = {}
def isDefinedAt(any: Any) = false
}
}
trait Errors extends Logger {
override def receive = super.receive orElse {
case "error" => log.info("received error")
}
}
trait Warns extends Logger {
override def receive = super.receive orElse {
case "warn" => log.info("received warn")
}
}
object Main extends App {
val system = ActorSystem("mysystem")
val actor = system.actorOf(Props(new Logger with Errors with Warns), name = "logger")
actor ! "error"
actor ! "warn"
}