2011-12-30 24 views
20

考慮以下兩個特點:在阿卡撰寫Scala的特質行爲收到方法

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) 
} 

現在考慮我可以創造一個實現兩個性狀的新演員:

val peekedpoked = actorRef(new Actor extends Poked with Peeked) 

如何撰寫了接收處理程序?即,接收器應該是類似下面的代碼,雖然「自動產生」(即,所有的性狀應該組成):

def receive = (Poked.receive: Receive) orElse (Peeked.receive: Receive) orElse ... 

回答

27

可以使用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! 

編輯:

響應於雨果的評論,這裏有一個解決方案,允許你以構成混入而無需手動接線其接收一起。基本上它涉及一個可變的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! 

要記住的唯一的事情是的順序接收不應是重要的,因爲你將不能夠很容易地預測哪一個是第一鏈,儘管你可以解決由使用可變的哈希映射而不是列表。

+0

這是非常有趣的,謝謝你:-)但它假定一個類型IntOrString這既是一個int和一個字符串的前生,而IntOrString知道應該撰寫那些(如果我正在構建一個框架,另一個可能會忽略)。是不是可以使IntActor和StringActor特徵自動組成? – 2011-12-30 20:19:33

+3

順序是由混合的特徵線性化給出的,因此「可預測的」;-)並且使用預先匹配匹配重寫後面的特徵。早些時候,所以我認爲你的解決方案非常好! – 2011-12-31 11:53:41

+0

優秀的scala-fu顯示! :-) – 2011-12-31 12:32:20

5

您可以在其基礎演員類和鏈接收中使用空接收定義。 樣品爲阿卡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" 
}