rap-2-h
rap-2-h

Reputation: 32038

Reference to unwrapped property fails: use of partially moved value: `self`

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

Upvotes: 2

Views: 2858

Answers (1)

Shepmaster
Shepmaster

Reputation: 431789

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())
    }
}

Upvotes: 6

Related Questions