While working through the OOP-Chapter of the Rust book (2nd Edition) I took on the optional task to implement the method add_text
for the following struct
pub struct Post {
state: Option<Box<State>>,
content: String,
}
There are three structs that implement the State
trait, but only the Draft
struct should actually do something. I implemented this as follows
trait State {
// snip
fn add_text(&self, post: &mut Post, text: &str) { }
}
struct Draft { }
impl State for Draft {
// snip
fn add_text(&self, post: &mut Post, text: &str) {
post.content.push_str(text);
}
}
My problem is that in order to get the State
from my post struct to call the add_text
method I immutably borrow self
(in Post
) and can not pass on a mutable reference to the add_text
method of the State
trait:
impl Post {
// snip
pub fn add_text(&mut self, text: &str){
let state = self.state.as_ref().unwrap(); // This immutably borrows self
state.add_text(self, text); // so that this mutable borrow is no longer possible
}
}
How do I deal with this dilemma? I definitely need a mutable reference to the Post
, otherwise I can't change its text. On the other hand, I need to get the State
first since otherwise I can not even call the method.
One way to work around this would be be to change add_text
to get_text_to_add
which would not require mutability of the Post
, but I would like to make sure that I am not overseeing any options to solve this.
With structs Rust is smart enough to be able to do disjoint borrows so you don't need to pass a mutable reference to the entire Post
struct, just the part of it you need to modify (in this case content).
trait State {
// snip
// Modify the method on the add_text trait so that it
// takes a mutable reference to String
fn add_text(&self, content: &mut String, text: &str) { }
}
struct Draft { }
impl State for Draft {
// snip
// Update the implementation of State for Draft so that it
// matches the new signature
fn add_text(&self, content: &mut String, text: &str) {
content.push_str(text);
}
}
impl Post {
// snip
pub fn add_text(&mut self, text: &str){
let state = self.state.as_ref().unwrap();
// Now when you call add_text you don't require a mutable
// reference to self, just to self.content and so the
// borrow checker is happy
state.add_text(&mut self.content, text);
}
}
This should work but it feels a bit forced, (as EvilTak points out the reference to self in Draft::add_text
is redundant). I guess that's part of the point of the exercise though; while it is possible to implement certain patterns from OOP in Rust there are better ways to model the problem.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.