- 模式
- Ask
- Transform
模式
Ask
Ask模式允许actor将actor发送到actor系统之外。 该值作为Future传递。
让我们来看看它是如何工作的:
extern crate riker_patterns;use riker_patterns::ask;struct MyActor;impl Actor for MyActor {type Msg = u32;fn receive(&mut self,ctx: &Context<Self::Msg>,msg: Self::Msg,sender: ActorRef<Self::Msg>) {// sender is the Ask, waiting to a message to be sent back to itsender.try_tell(msg * 2, Some(ctx.myself()));}}fn main() {let model: DefaultModel<u32> = DefaultModel::new();let sys = ActorSystem::new(&model).unwrap();let props = MyActor::props();let my_actor = sys.actor_of(props, "my-actor");// ask returns a future that automatically is driven// to completion by the system.let res = ask(&sys, &my_actor, 100);// the result future can be passed to a library or fuction that// expects a future, or it can be extracted locally using `block_on`.let res = block_on(res).unwrap();println!("The result value is: {}", res);}
在背后,Ask设置了一个临时的中级 Actor,该 Actor在问的一生中生活。其他 Actor将此临时 Actor视为发件人,并可以向其发送消息。当临时询问者收到一条消息时,它会完成未完成的 Future,并自行停止清理。
当您拥有在actor系统之外运行的应用程序的一部分时,或者在另一个actor系统中,例如服务于API请求的Web服务器(例如Hyper)时,Ask特别有用。然后可以将生成的 Future链接为 Future堆栈的一部分。
Transform
变换使得基于其当前状态的 Actor行为更容易被推理。由于参与者维持状态,并且确实是主要关注点,因此能够基于该状态以不同方式处理消息非常重要。 Transform模式通过为每个状态专用接收函数来分离消息处理。这节省了过多的匹配以处理几种可能的状态,即处理行为在状态改变时而不是在每个消息接收时被抢占。
信息 : 如果你熟悉JVM上的Akka,变换就像变成了。
#[macro_use]extern crate riker_patterns;use riker_patterns::ask;#[derive(Clone, Debug)]enum MyMsg {SetPassword(String), // passwordAuthenticate(String), // password}impl Into<ActorMsg<MyMsg>> for MyMsg {fn into(self) -> ActorMsg<MyMsg> {ActorMsg::User(self)}}struct UserActor {username: String,password: Option<String>,// rec field is required to store current method to be usedrec: Receive<UserActor, MyMsg>,}impl UserActor {fn actor(username: String) -> BoxActor<MyMsg> {let actor = UserActor {username,password: None,rec: Self::created, // <-- set initial method to `created` stated};Box::new(actor)}fn props(username: String) -> BoxActorProd<MyMsg> {Props::new_args(Box::new(UserActor::actor), username)}/// Receive method for this actor when it is in a created state/// i.e. password has not yet been set.fn created(&mut self,ctx: &Context<MyMsg>,msg: MyMsg,sender: Option<ActorRef<MyMsg>>) {match msg {MyMsg::SetPassword(passwd) => {self.password = Some(passwd);// send back a result to sender// e.g. `sender.try_tell(Ok, None);`// transform behavior to active statetransform!(self, UserActor::active);}MyMsg::Authenticate(passwd) => {// `MyMsg::Authenticate` is invalid since no user password// has been set.// Signal that this is an error for the current stateself.probe.as_ref().unwrap().0.event(ProbeMsg::Err);}}}/// Receive method for this actor when a password has been set/// and the user account is now active.fn active(&mut self,ctx: &Context<MyMsg>,msg: MyMsg,sender: Option<ActorRef<MyMsg>>) {match msg {MyMsg::Authenticate(passwd) => {// send back an authentication result to sender// e.g. `sender.try_tell(Ok, None);`// signal that this is correctself.probe.as_ref().unwrap().0.event(ProbeMsg::Ok);}MyMsg::SetPassword(passwd) => {// set a new passwordself.password = Some(passwd);}}}}impl Actor for UserActor {type Msg = MyMsg;fn receive(&mut self,ctx: &Context<Self::Msg>,msg: Self::Msg,sender: Option<ActorRef<Self::Msg>>) {// just call the currently set transform function(self.rec)(self, ctx, msg, sender)}}
注意 : 改造! 宏期望将self上当前接收函数的字段名称命名为rec。 使用不同的名称很容易,也可以使用自己的宏,或者只使用标准代码设置功能。 变换的优势! 因为它与标准代码不同,所以在转换发生时很容易阅读和识别。
