0

It seems I don't get the borrowing concept in Rust. I have this simple example:

pub struct User {
    name: Option<String>,
}

impl User {
    pub fn new() -> Self {
        Self {
            name: Some("".to_string()),
        }
    }

    pub fn write_name(&mut self) -> Result<(), &str> {
        let name = self.generate_name()?;
        self.name = Some(name);
        Ok(())
    }

    pub fn generate_name(&self) -> Result<String, &str> {
        Ok("John".to_string())
    }
}
error[E0506]: cannot assign to `self.name` because it is borrowed
  --> src/lib.rs:14:9
   |
12 |     pub fn write_name(&mut self) -> Result<(), &str> {
   |                       - let's call the lifetime of this reference `'1`
13 |         let name = self.generate_name()?;
   |                    ----                - returning this value requires that `*self` is borrowed for `'1`
   |                    |
   |                    borrow of `self.name` occurs here
14 |         self.name = Some(name);
   |         ^^^^^^^^^ assignment to borrowed `self.name` occurs here

I need to return Result and I need to split name generation from setting name. How can I release borrowing so I can set the self.name variable?

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
xpepermint
  • 35,055
  • 30
  • 109
  • 163
  • I'm not a rust expert but i think the problem is on the error side of the result, because you are borrwing an str – Fanto Apr 06 '20 at 17:55

1 Answers1

2

The function header

pub fn generate_name(&self) -> Result<String, &str>

should probably be changed to

pub fn generate_name(&self) -> Result<String, &'static str>

The former makes the compiler assume that the lifetime of the error type &str is tied to the lifetime of self, so self is considered borrowed on the call site until the result goes out of scope. It's unlikely that your error type is supposed to borrow self – you much more likely want to return a static string as an error instead.

Your defintion of generate_name() has an implicit lifetime parameter in the argument list – the lifetime of the self reference – and an implicit lifetime parameter in the return type – the lifetime of the error type &str. If there is exactly one free lifetime parameter in both the argument list and the return type, the compiler applies a lifetime elision rule that identifies the free lifetime parameters, since this is most likely what you want. If it isn't what you want, like in this case, you need to explicitly state the desired lifetimes.

Sven Marnach
  • 574,206
  • 118
  • 941
  • 841
  • I see now, thanks. Btw, the other way I found is also using `clone` function so I can do `let name = x.generate_name().unwrap().clone();` and it seems it releases the reference too. – xpepermint Apr 06 '20 at 18:05