开发者

Sending a None back to the caller from an Actor

开发者 https://www.devze.com 2023-04-04 20:23 出处:网络
I have a simple Actor that queries a database using ScalaQuery, which I\'ve mocked for a test of a client using it.

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(_)

0

精彩评论

暂无评论...
验证码 换一张
取 消