2
votes

I try to send an unwrapped string reference to a static method implemented for a struct. Here is a simplified code:

fn main() {
    let a = A {p: Some("p".to_string())};
    a.a();
}

struct A {
    p: Option<String>
}

impl A {
    fn a(self) -> Self {
        Self::b(&self.p.unwrap());
        self
    }
    fn b(b: &str) {
        print!("b: {}", b)
    }
}

It fails:

error[E0382]: use of partially moved value: `self`
  --> src/main.rs:14:13
   |
13 |             Self::b(&self.p.unwrap());
   |                      ------ value moved here
14 |             self
   |             ^^^^ value used here after move
   |
   = note: move occurs because `self.p` has type `std::option::Option<std::string::String>`, which does not implement the `Copy` trait

I think implementing the Copy trait is not a solution. How can I unwrap p and pass it as a &str to b in that context?

I changed my code as suggested in Can't borrow File from &mut self (error msg: cannot move out of borrowed content):

fn main() {
    let a = A {p: Some("p".to_string())};
    a.a();
}

struct A {
    p: Option<String>
}

impl A {
    fn a(self) -> Self {
        let c = self.p.as_ref().unwrap();
        Self::b(&c);
        self
    }
    fn b(b: &str) {
        print!("b: {}", b)
    }
}

Which results in a different error:

error[E0505]: cannot move out of `self` because it is borrowed
  --> src/main.rs:15:13
   |
13 |             let c = self.p.as_ref().unwrap();
   |                     ------ borrow of `self.p` occurs here
14 |             Self::b(&c);
15 |             self
   |             ^^^^ move out of `self` occurs here
1
as_ref() would probably be better here than the duplicate's suggestion, since you want a &str not a &mut str or &mut String.Aurora0001
@Aurora0001 I tried to add as_ref() but it still does not work (maybe I misunderstood something) play.integer32.com/…rap-2-h

1 Answers

5
votes

As discussed in Can't borrow File from &mut self (error msg: cannot move out of borrowed content), you can't call unwrap on a borrowed value because unwrap takes ownership of the value.

Changing to as_ref borrows from the value self. You are not allowed to move a value (which includes returning that value) while any references to it are outstanding. That means you need to constrain the life of the borrow to end before the value needs to be moved:

fn a(self) -> Self {
    {
        let c = self.p.as_ref().unwrap();
        Self::b(c);
    }
    self
}

It may be an artifact of your example, but the code is pretty strange. I'd have written it as

impl A {
    fn a(self) -> Self {
        self.b();
        self
    }

    fn b(&self) {
        print!("b: {}", self.p.as_ref().unwrap())
    }
}

Or

impl A {
    fn a(&self) {
        print!("a: {}", self.p.as_ref().unwrap())
    }
}