Confused by third extension exercise in Rust book Ch17.3

#1

Hi,

I’m working my way through the Rust book v2 (which is amazing btw!). Ch17.3 has three exercises under “Trade-offs of the State Pattern”. I’m trying to do the third of them “Allow users to add text content only when a post is in the Draft state”.

The general solution (hinted in the book) seems to be to have Post’s add_text() method defer to the current state object, which can then call back to the Post to actually manipulate the content (should it want to). This is how Post::content() works, except that’s all read-only. Post::add_text -> State::add_text -> Post::_add_text() needs to alter the content field of Post.

I tried two ways:

The first tries to get _add_text() a mut reference to the Post:

impl Post {
    fn add_text(&mut self, text: &str) {
        self.state.as_ref().unwrap().add_text(self, text);
    }
    fn _add_text(&mut self, text: &str) {
        self.content.push_str(text);
    }
}
impl State for Draft {
    fn add_text(&self, post: &mut Post, text: &str) -> () {
        post._add_text(text);
    }
}

The problem here is that self.state.as_ref().unwrap().add_text(self, text); tries to borrow self twice, once mutably, which isn’t allowed.

The other approach I tried was to have immutable references to Post and State, but have Post::content be a RefCell for interior mutability. In this case everything is fine except I can’t get the value of Post::content. I don’t want to clone() it, and I don’t seem to be able to borrow it. I ultimately end up with the following code:

impl State for Published {
    fn content<'a>(&self, post: &'a Post) -> &'a str {
        &post.content.borrow()
    }
}

and the temporary Ref returned by borrow() doesn’t live long enough.

Help!

Can anyone make either solution build?
I know it’s been talked about, but solutions to the book exercises would be really helpful!

Thanks,
matt