模式

Ask

Ask模式允许actoractor发送到actor系统之外。 该值作为Future传递。

让我们来看看它是如何工作的:

  1. extern crate riker_patterns;
  2. use riker_patterns::ask;
  3. struct MyActor;
  4. impl Actor for MyActor {
  5. type Msg = u32;
  6. fn receive(&mut self,
  7. ctx: &Context<Self::Msg>,
  8. msg: Self::Msg,
  9. sender: ActorRef<Self::Msg>) {
  10. // sender is the Ask, waiting to a message to be sent back to it
  11. sender.try_tell(msg * 2, Some(ctx.myself()));
  12. }
  13. }
  14. fn main() {
  15. let model: DefaultModel<u32> = DefaultModel::new();
  16. let sys = ActorSystem::new(&model).unwrap();
  17. let props = MyActor::props();
  18. let my_actor = sys.actor_of(props, "my-actor");
  19. // ask returns a future that automatically is driven
  20. // to completion by the system.
  21. let res = ask(&sys, &my_actor, 100);
  22. // the result future can be passed to a library or fuction that
  23. // expects a future, or it can be extracted locally using `block_on`.
  24. let res = block_on(res).unwrap();
  25. println!("The result value is: {}", res);
  26. }

在背后,Ask设置了一个临时的中级 Actor,该 Actor在问的一生中生活。其他 Actor将此临时 Actor视为发件人,并可以向其发送消息。当临时询问者收到一条消息时,它会完成未完成的 Future,并自行停止清理。

当您拥有在actor系统之外运行的应用程序的一部分时,或者在另一个actor系统中,例如服务于API请求的Web服务器(例如Hyper)时,Ask特别有用。然后可以将生成的 Future链接为 Future堆栈的一部分。

Transform

变换使得基于其当前状态的 Actor行为更容易被推理。由于参与者维持状态,并且确实是主要关注点,因此能够基于该状态以不同方式处理消息非常重要。 Transform模式通过为每个状态专用接收函数来分离消息处理。这节省了过多的匹配以处理几种可能的状态,即处理行为在状态改变时而不是在每个消息接收时被抢占。

信息 : 如果你熟悉JVM上的Akka,变换就像变成了。

  1. #[macro_use]
  2. extern crate riker_patterns;
  3. use riker_patterns::ask;
  4. #[derive(Clone, Debug)]
  5. enum MyMsg {
  6. SetPassword(String), // password
  7. Authenticate(String), // password
  8. }
  9. impl Into<ActorMsg<MyMsg>> for MyMsg {
  10. fn into(self) -> ActorMsg<MyMsg> {
  11. ActorMsg::User(self)
  12. }
  13. }
  14. struct UserActor {
  15. username: String,
  16. password: Option<String>,
  17. // rec field is required to store current method to be used
  18. rec: Receive<UserActor, MyMsg>,
  19. }
  20. impl UserActor {
  21. fn actor(username: String) -> BoxActor<MyMsg> {
  22. let actor = UserActor {
  23. username,
  24. password: None,
  25. rec: Self::created, // <-- set initial method to `created` stated
  26. };
  27. Box::new(actor)
  28. }
  29. fn props(username: String) -> BoxActorProd<MyMsg> {
  30. Props::new_args(Box::new(UserActor::actor), username)
  31. }
  32. /// Receive method for this actor when it is in a created state
  33. /// i.e. password has not yet been set.
  34. fn created(&mut self,
  35. ctx: &Context<MyMsg>,
  36. msg: MyMsg,
  37. sender: Option<ActorRef<MyMsg>>) {
  38. match msg {
  39. MyMsg::SetPassword(passwd) => {
  40. self.password = Some(passwd);
  41. // send back a result to sender
  42. // e.g. `sender.try_tell(Ok, None);`
  43. // transform behavior to active state
  44. transform!(self, UserActor::active);
  45. }
  46. MyMsg::Authenticate(passwd) => {
  47. // `MyMsg::Authenticate` is invalid since no user password
  48. // has been set.
  49. // Signal that this is an error for the current state
  50. self.probe.as_ref().unwrap().0.event(ProbeMsg::Err);
  51. }
  52. }
  53. }
  54. /// Receive method for this actor when a password has been set
  55. /// and the user account is now active.
  56. fn active(&mut self,
  57. ctx: &Context<MyMsg>,
  58. msg: MyMsg,
  59. sender: Option<ActorRef<MyMsg>>) {
  60. match msg {
  61. MyMsg::Authenticate(passwd) => {
  62. // send back an authentication result to sender
  63. // e.g. `sender.try_tell(Ok, None);`
  64. // signal that this is correct
  65. self.probe.as_ref().unwrap().0.event(ProbeMsg::Ok);
  66. }
  67. MyMsg::SetPassword(passwd) => {
  68. // set a new password
  69. self.password = Some(passwd);
  70. }
  71. }
  72. }
  73. }
  74. impl Actor for UserActor {
  75. type Msg = MyMsg;
  76. fn receive(&mut self,
  77. ctx: &Context<Self::Msg>,
  78. msg: Self::Msg,
  79. sender: Option<ActorRef<Self::Msg>>) {
  80. // just call the currently set transform function
  81. (self.rec)(self, ctx, msg, sender)
  82. }
  83. }

注意 : 改造! 宏期望将self上当前接收函数的字段名称命名为rec。 使用不同的名称很容易,也可以使用自己的宏,或者只使用标准代码设置功能。 变换的优势! 因为它与标准代码不同,所以在转换发生时很容易阅读和识别。