Sending a None back to the caller from an Actor
I have a simple Actor that queries a database using ScalaQuery, which I've mocked for a test of a client using it.
What I want is for the (mock) Actor to reply with Some(MyObject)
if the ID matches up, and None
otherwise. However, I can't figure out how to make this work. Here's the code I have so far:
def receive = {
case FetchSomething(someId) => {
if (someId == 1234) self.channel ! someObject
else self.channel ! None
}
}
However, instead of returning None
in the client code, it returns Some(None)
- which, of course, confuses my client. How I want the client to work is something like this:
val object = persister !! FetchSomething(1337) match {
case myObject: Some[MyObject] => myObject
case _ => None
}
(of course, the above may just be wrong - instead of Some
, it could be Option
)
How can I achieve this? Perhaps more specific, how can I send a None
back through self.channel so when matching it, it's None
and 开发者_开发百科not Some(None)
?
The fault is in the client, which misinterpret the reply, not following AKKA protocol. From the Akka documentation :
The !! method returns an Option[Any] which will be either Some(result) if returning successfully, or None if the call timed out.
So if reply is None, client Some(None). If reply is Some(12) you get Some(Some(12)). If client receives None, it should not means the actor replied None, it means the actor did not reply.
This is AKKA protocol, and it means client should process reply with
case Some(answer) => process answer
case None => actor did not reply
Then if your actor happens to reply with an Option[Something], that is your protocol, which is another layer:
case Some(answer) => /* your protocol */ answer match {
case Some(actualValue) => reply had actualValue
case None => None was the reply
}
case None => actor did not reply
Which of course, you can also write
case Some(Some(actualValue)) =>
case Some(None) =>
case None =>
A side note, do not match with x: Some[A]
(do not give the type parameter when matching on a generic type). It does not work, it will not verify that you have a Some[Something]
, but not that Something
is A
(see type erasure, the compiler gives a warning). You want to match with case Some(x: A)
which gives you the content of the Some
in x
, what you normally want. If you actually want the Some
rather than its content, case s @ Some(x: A)
will bind s
to the Some
instance, x
to its content. Use _
instead of x if you are not interested in it.
If it is known that the type inside the option is A
, then do not mention it, just write
case Some(x)
, case s: Some(_)
精彩评论