why do we need to call take() for Option<T> variable

我只是一个虾纸丫 提交于 2020-05-30 07:50:06

问题


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?


回答1:


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, 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.




回答2:


If request_review panic, it will lead to free the Box twice, first in request_review and then when the Option is freed.



来源:https://stackoverflow.com/questions/57193489/why-do-we-need-to-call-take-for-optiont-variable

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!