为何Post的state需用Option<Box<...>>包裹?独立程序旧state访问疑问
为什么Post的request_review方法需要先take() state而不是直接赋值?
先看书中给出的代码:
impl Post { // --snip-- pub fn request_review(&mut self) { if let Some(s) = self.state.take() { self.state = Some(s.request_review()) } } } trait State { fn request_review(self: Box<Self>) -> Box<dyn State>; }
你疑惑的点是:为什么不能直接写self.state = self.state.request_review();,而是要先把state临时设为None,难道赋值后Post还能访问旧的state?
核心原因是Rust的所有权规则不允许直接这么写,根本到不了“运行时访问旧state”那一步,直接写法会编译失败,具体原因如下:
- 方法的所有权要求:
Statetrait的request_review方法签名是fn request_review(self: Box<Self>) -> Box<dyn State>,这意味着它需要拿走Box<Self>的所有权才能调用——调用这个方法会直接消耗掉原来的state实例。 - 直接赋值的所有权冲突:如果尝试写
self.state = self.state.request_review();,这里的self.state是Option<Box<dyn State>>类型。当你调用self.state.request_review()时,需要把Box<dyn State>从Option中取出来并转移所有权给方法,但此时self是&mut self(可变引用),Rust不允许在持有可变引用的情况下直接移动字段的所有权——因为可变引用要求独占访问,而移动所有权会让原字段处于无效状态,这违反了Rust的内存安全规则。 - take()的作用:
self.state.take()会把Option中的值取走,同时将self.state设置为None。这一步合法地获取了state的所有权(take()方法的签名是fn take(&mut self) -> Option<T>,它通过可变引用修改Option,取出内部值)。拿到所有权后,我们可以安全地调用request_review消耗旧state、生成新state,最后再把新state放回self.state中。
总结一下:不是担心运行时Post能访问旧state,而是直接写法在编译阶段就会被Rust拒绝,因为它违反了所有权和借用规则。用take()的方式是在遵守Rust规则的前提下,完成状态转换的唯一合法途径。
内容的提问来源于stack exchange,提问作者Mark
相关产品推荐
相关产品推荐

