• 模式
    • Ask
    • Transform

    模式

    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。 使用不同的名称很容易,也可以使用自己的宏,或者只使用标准代码设置功能。 变换的优势! 因为它与标准代码不同,所以在转换发生时很容易阅读和识别。