Instantiating and starting a Scala Actor in a Map
I'm experimenting with a map of actors, and would like to know how to instantiate them and start them in one fell swoop...
import scala.actors.Actor
import scala.actors.Actor._
import scala.collection.mutable._
abstract class Message
case class Update extends Message
object Test {
val groupings = "group1" :: "group2" :: "group3":: Nil
val myActorMap = new HashMap[String,MyActor]
def main(args : Array[String]) {
groupings.foreach(group => myActorMap += (group -> new MyActor))
myActorMap("group2").start
myActorMap("group2") ! Update
}
}
class MyActor extends Actor {
def act() {
loop {
react {
case Update =>
println("Received Update")
case _ =>
println("Ignoring event")
}
}
}
}
The line:
myActorMap("group2").start
will grab the second instance, and let me start it, but I would like to be able to do something more like:
groupings.foreach(group => myActorMap += (group -> (new MyActo开发者_StackOverflow中文版r).start))
but no matter how I wrap the new Actor, the compiler complains with something along the lines of:
type mismatch; found : scala.actors.Actor required: com.myCompany.test.MyActor
or various other complaints. I know it must be something simple to do with anonymous classes, but I can't see it right now. Any suggestions? Thanks in advance!!
The problem with start
is that it doesn't know the true type of your actor. Thus, it returns a generic one. To get around this, you need a compact way to start it and still return the actor you actually have (not a superclass). Actually, that sounds like a useful capability in general, doesn't it?--to take an object, have it do something, and then return the object?
class SideEffector[A](a: A) {
def effect(f: A => Unit) = { f(a); a }
}
implicit def everythingHasSideEffects[A](a: A) = new SideEffector(a)
Now you can
(new MyActor).effect(_.start)
and the type will be preserved. (If you're not using Scalaz, this sort of capability is so useful in general that you may want to drop it into your personal library of handy code snippets. It's in mine. You have one, don't you?)
How about this:
def main(args : Array[String]) {
groupings.foreach {
group =>
val actor = new MyActor
actor.start
myActorMap += (group -> actor)
}
myActorMap("group2") ! Update
}
精彩评论