Fighting the Borro Checker, again - Elegance?

I think I can see the cause of the error: Some(ref p) = self.p takes a immutable borrow of self and whilst in scope the mutable borrow in signature of use_p conficts.

How to I elegantly solve this? If the option p is not None I wish to use it.

See below for my inelegant solution…

struct Foo {
    p:Option<String>,
}
impl Foo {
    fn bar(&mut  self) {
        if let Some(ref p) = self.p {
            let p:String = p.clone();
            self.use_p(p.as_str());
        }
    }
    fn use_p(&mut self, p:&str){
        println!("{}", p);
        self.p = None;
    }
}
6 |         if let Some(ref p) = self.p {
  |                     ----- immutable borrow occurs here
7 |             let p:String = p.clone();
8 |             self.use_p(p.as_str());
  |             ^^^^ mutable borrow occurs here
9 |         }
  |         - immutable borrow ends here
6 |         if let Some(ref p) = self.p {
  |                     ----- immutable borrow occurs here
7 |             let p:String = p.clone();
8 |             self.use_p(p.as_str());
  |             ^^^^ mutable borrow occurs here
9 |         }
  |         - immutable borrow ends here

The solution…

    fn bar(&mut  self) {
        let mut s = "".to_string();
        if let Some(ref p) = self.p {
            s = p.clone();
        }
        if s.len() > 0 {
            self.use_p(s.as_str());
        }
    }

I have to introduce a superfluous mutable variable s for no reason other than getting past the borrow checker. There must be a better way, is there a better way? What is the better way?

Since you’re cloning anyway, just do that on the Option – it’s trivial for None, and otherwise no worse for the Some(String).

    fn bar(&mut  self) {
        if let Some(ref p) = self.p.clone() {
            self.use_p(p.as_str());
        }
    }
1 Like

Not sure if this works (haven’t tried compiling), but here’s another idea:

fn bar(&mut self) {
    self.p
        // Does it make sense in your program to remove `p` from the `use_p` method?
        .take()
        // Do you need to `clone()`? if it's taken by ref you shouldn't have to
        .map(|p| self.use_p(&p.clone()));
        // ignore the returned `Option`
}

(yay you like elegance too!)

Clone the option… So I do not take ownership of self. Yep! That is the better way!