In this piece of code:
pub struct Post {
state: Option<Box<dyn State>>,
content: String,
}
impl Post {
pub fn new() -> Post {
Post {
state: Some(Box::new(Draft {})),
content: String::new(),
}
}
pub fn add_text(&mut self, text: &str) {
self.content.push_str(text);
}
pub fn content(&self) -> &str {
""
}
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>;
}
struct Draft {}
impl State for Draft {
fn request_review(self: Box<Self>) -> Box<dyn State> {
Box::new(PendingReview {})
}
}
struct PendingReview {
fn request_review(self: Box<Self>) -> Box<dyn State> {
self
}
}
there is a call to take()
; the book says:
To consume the old state, the request_review method needs to take ownership of the state value. This is where the Option in the state field of Post comes in: we call the take method to take the Some value out of the state field and leave a None in its place.
We need to set state to None temporarily rather than setting it directly with code like
self.state = self.state.request_review();
to get ownership of the state value. This ensures Post can’t use the old state value after we’ve transformed it into a new state.
How is it possible that Post
uses its old state if we set it directly?
If you code like this:
pub struct Post {
state: Box<dyn State>,
content: String,
}
trait State {
fn request_review(self: Box<Self>) -> Box<dyn State>;
}
impl Post {
// ...
pub fn request_review(&mut self) {
self.state = self.state.request_review();
}
// ...
}
You will get a compiler error:
self.state = self.state.request_review();
^^^^^^ move occurs because `self.state` has type `std::boxed::Box<dyn State>`, which does not implement the `Copy` trait'.
This is because calling State::request_review
will move Box<self>
, which is allocated on heap, and Rust doesn't allow you to just move values away from heap unless you implement Copy
, otherwise what's left there? The book uses Option::take()
to move ownership out and leave None
on the place.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With