Search code examples
rustownershipborrow-checker

Ownership error using builder pattern


I tried to write an API following the Builder pattern the example is much simplified but still the compliler complains that a borrowed value does not live long enough.

#[derive(Debug)]
pub struct MediaType {
    toptype: Option<String>,
    subtype: Option<String>,
}

impl MediaType {
    pub fn new() -> MediaType {
        MediaType {
            toptype: None,
            subtype: None,
        }
    }

    pub fn toptype<'a>(&'a mut self, toptype: Option<String>) -> &'a mut MediaType {
        self.toptype = toptype;
        self
    }
    pub fn subtype<'a>(&'a mut self, subtype: Option<String>) -> &'a mut MediaType {
        self.subtype = subtype;
        self
    }
}


fn main() {
    let mut tag =  MediaType::new().toptype(Some("text".to_owned())).subtype(Some("html".to_owned()));
    println!("{:?}", tag);
}

The resulting error message is:

<anon>:27:20: 27:36 error: borrowed value does not live long enough
<anon>:27     let mut tag =  MediaType::new().toptype(Some("text".to_owned())).subtype(Some("html".to_owned()));
                             ^~~~~~~~~~~~~~~~
<anon>:27:103: 29:2 note: reference must be valid for the block suffix following statement 0 at 27:102...
<anon>:27     let mut tag =  MediaType::new().toptype(Some("text".to_owned())).subtype(Some("html".to_owned()));
<anon>:28     println!("{:?}", tag);
<anon>:29 }
<anon>:27:5: 27:103 note: ...but borrowed value is only valid for the statement at 27:4
<anon>:27     let mut tag =  MediaType::new().toptype(Some("text".to_owned())).subtype(Some("html".to_owned()));
              ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
<anon>:27:5: 27:103 help: consider using a `let` binding to increase its lifetime
<anon>:27     let mut tag =  MediaType::new().toptype(Some("text".to_owned())).subtype(Some("html".to_owned()));
              ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
error: aborting due to previous error
playpen: application terminated with error code 101

both using a two liner

let mut tag = MediaType::new();
tag.toptype(Some("text".to_owned())).subtype(Some("html".to_owned()));

and directly printing MediaType

println!("{:?}", MediaType::new().toptype(Some("text".to_owned())).subtype(Some("html".to_owned())));

do work. Why does the borrow checker complain although it does not complain when directly using the value and I followed the builder pattern example?

Rust Playground


Solution

  • Because you don't store the builder anywhere. If it's not stored anywhere, it only exists for, at most, the duration of that expression. So at the end of the expression, you have a &mut MediaType pointing to a value that is about to be destroyed.

    If you look at the example in the linked doc, the author either uses the builder entirely in a single expression or he stores the result of the ::new() call. You can't borrow a temporary and then store that borrow.