I noticed it is legal to write this scala
code:
val fussyActor = actor {
loop {
receive {
case s: String => println("I got a String: " + s)
case _ => println("I have no idea what I just got.")
}
}
}
I know from documentation that actor
is a trait, which has loop
and receive
value members. But how is it possible to stack these methods like above? Is it implementing or overriding these methods? I am quite confused at this syntax. Please provide some good references/pointers.
First, a standard disclaimer. Scala Actors have been deprecated in favor of Akka Actors. If you want to continue down the path of learning to use Actors with Scala, you should look into Akka instead of researching Scala Actors.
Now, about your question. There are a couple of things in play here, so let's first start out with what you need to do in order to define a new Scala Actor. If you look at the Scala Actor trait, you see that there is one abstract method that you must provide called act():Unit
. This is a method that takes no inputs and returns no inputs. It defines the actors behavior. So in it's simplest form, a custom Scala Actor could be:
class MyActor extends Actor{
def act(){
}
}
Now this not a very interesting actor as it does nothing. Now, one way to provide behavior is to invoke the receive
method, providing a PartialFunction[Any,R]
where R is a generic return type. You could do that like so:
class MyActor extends Actor{
def act(){
receive{
case "foo" => println("bar")
}
}
}
So now if this actor receives a message "foo", it will print "bar". The problem here is that this will only happen for the first message and then won't do anything after. To fix that. we can wrap our call to receive
with a call to loop
to make it continue to do the provided receive
call for each received message:
class MyActor extends Actor{
def act(){
loop{
receive{
case "foo" => println("bar")
}
}
}
}
So this is now starting to look like your example a bit more. We are leveraging the loop
and receive
methods that come with the Actor
trait in order to give this actor behavior. Lastly, instead of defining an explicit class as my actor, I can define one on the fly with the actor
method on the Actor
companion object. That method takes a function body that will be used as the act
impl like this:
def actor(body: => Unit){
val a = new Actor {
def act() = body
override final val scheduler: IScheduler = parentScheduler
}
}
So in your example, you are creating a new actor implementation on the fly and providing an impl for act
that will loop and call receive
continually with the partial function you supplied for message handling.
Hopefully this clarifies things a bit. The only method you are "overriding" (providing an impl for) is act
. When you see loop
and receive
, those are not overrides; they are simply calls to those existing methods on the Actor
trait.
Actually it's illegal without import Actor._
.
Your code without that import:
val fussyActor = Actor.actor {
Actor.loop {
Actor.receive { ... }
}
}
actor
, loop
and receive
are methods of object Actor
.
def actor(body: ⇒ Unit): Actor
def loop(body: ⇒ Unit): Unit
def receive[A](f: PartialFunction[Any, A]): A
Method actor
accepts by-name
Untit
parameter body
- some code block to execute in separate thread and creates an Actor
with act
method implemented using parameter body
.
Method loop
accepts by-name
Untit
parameter body
- some code block to execute in infinite loop.
Method receive
accepts PartialFunction
as parameter f
and calls f
with message as parameter. It takes message from actor associated with current thread.
Note that scala actors are deprecated, you should use akka actors. See The Scala Actors Migration Guide .
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.