这里为什么要Option,看完教程还是不懂?
教程:
pub struct Post {
state: Option<Box<dyn State>>,
content: String,
}
这里为什么需要Option呢? 通过观察整个源码得知,这里state是不可能为空,所以根据我的理解这里是不需要用到Option的。
但是当我把Option去掉时,出现以下情况。
pub fn request_review(&mut self) {
// if let Some(t) = self.state.take() {
// self.state = Some(t.request_review())
// }
self.state = self.state.request_review();
}
编译提示:
error[E0507]: cannot move out of `self.state` which is behind a mutable reference
--> src\lib.rs:26:22
|
26 | self.state = self.state.request_review();
| ^^^^^^^^^^ move occurs because `self.state` has type `Box<dyn State>`, which does not implement the `Copy` trait
self.state
这里发生了移动,那我该如何解决这个问题呢,解决这个问题有几种解决方式?
还有一个问题,Option使用场景有哪些?
完整源码
main.rs
use oop_exercise::Post;
fn main() {
let t = "I love China!";
let mut post = Post::new();
post.add_content(t);
assert_eq!("", post.content());
post.request_review();
assert_eq!("", post.content());
post.approve();
assert_eq!(t, post.content());
}
lib.rs
pub struct Post {
state: Option<Box<dyn State>>,
content: String,
}
impl Post {
pub fn new() -> Post {
Post {
state: Some(Box::new(DraftPost {})),
content: String::new()
}
}
pub fn add_content(&mut self, content: &str) {
self.content.push_str(content);
}
pub fn content(&self) -> &str {
self.state.as_ref().unwrap().content(self)
}
pub fn request_review(&mut self) {
if let Some(t) = self.state.take() {
self.state = Some(t.request_review())
}
}
pub fn approve(&mut self) {
if let Some(t) = self.state.take() {
self.state = Some(t.approve())
}
}
}
trait State {
fn content<'a>(&self, _post: &'a Post) -> &'a str {
""
}
fn request_review(self: Box<Self>) -> Box<dyn State>;
fn approve(self: Box<Self>) -> Box<dyn State>;
}
struct DraftPost {
}
struct PendingReviewPost {
}
struct PublishedPost {
}
impl State for DraftPost {
fn request_review(self: Box<Self>) -> Box<dyn State> {
Box::new(PendingReviewPost {})
}
fn approve(self: Box<Self>) -> Box<dyn State> {
self
}
}
impl State for PendingReviewPost {
fn request_review(self: Box<Self>) -> Box<dyn State> {
self
}
fn approve(self: Box<Self>) -> Box<dyn State> {
Box::new(PublishedPost {})
}
}
impl State for PublishedPost {
fn content<'a>(&self, post: &'a Post) -> &'a str {
post.content.as_str()
}
fn request_review(self: Box<Self>) -> Box<dyn State> {
self
}
fn approve(self: Box<Self>) -> Box<dyn State> {
self
}
}
1
共 3 条评论, 1 页
评论区
写评论这篇教程主要从OO的角度去实现,上面的朋友也解释了为什么用
Option
,注意这里不是不会出现None
,在self.state.take()
后,在self.state = ...
之前post
中的state
是存在None的情况。另:教程从动态的角度去设计
State
,如果从可读性和实用的角度,实际上这里使用enum
会更合理:注意:设计
State
采用了Copy
语义(State
此时的大小只有一个字节,其实和u8
一样)楼上是正解~
关键在于 state 字段的值需要改变,且这个改变发生在 lib crate 中,而无需 使用者更改。
我试着用
RefCell
达到内部可变性,从而替代了Option
。当然,从效率上说,肯定Option
的方式更高。--
👇
Aya0wind: 因为这两个操作是不一样的,你看看Option::take()的文档里写了这句话
Takes the value out of the option, leaving a [None] in its place. 用了Option你才可以把使用&mut self把state的值move出来,然后在原来的位置留一个None,不用Option你是无法move一个已经被borrow的对象的成员的。 Option应用场景那太广了,只要是表示可空的语义都可以用,你这个例子其实也是因为state可空,因为你需要使用一个mut借用来move其成员。如果不用Option,state被你move走了,而你却只有一个self的借用,并不能保证出了函数之后self就不会被使用了。那么势必产生一个使用被move了的对象的可能性,放到C/C++里就是use after move的错误。而用Option就可以留一个None值在里面,外面使用它就需要判空了。
因为这两个操作是不一样的,你看看Option::take()的文档里写了这句话
Takes the value out of the option, leaving a [None] in its place. 用了Option你才可以把使用&mut self把state的值move出来,然后在原来的位置留一个None,不用Option你是无法move一个已经被borrow的对象的成员的。 Option应用场景那太广了,只要是表示可空的语义都可以用,你这个例子其实也是因为state可空,因为你需要使用一个mut借用来move其成员。如果不用Option,state被你move走了,而你却只有一个self的借用,并不能保证出了函数之后self就不会被使用了。那么势必产生一个使用被move了的对象的可能性,放到C/C++里就是use after move的错误。而用Option就可以留一个None值在里面,外面使用它就需要判空了。