Value does not live long enough

24,785

The scope of b is the new function, so its memory will be freed when the function returns. But you are trying to return a reference to b from that function. If Rust let you do this, the only code that could possibly use that reference would use it after the value is invalid. The borrow checker is protecting you from undefined behaviour.

Making layout to be &'static str sounds like you are making things simple, but it is unreasonable to expect the dynamically allocated memory from regex.replace_all to be static. Without getting into unsafe code, you should consider anything in the 'static lifetime to be a compile-time constant. For example, a string literal.

As others have said, you probably want layout to be a String. A String is similar to &str, but it owns the underlying str. That means when you move the String, the underlying str moves with it. A &str is a reference and must not outlive the owner of the str that it points to.


If you really want it to be &str, an alternative but less ergonomic approach is to have the caller of new() own the &str, and pass it in as a mutable reference.

pub struct Formatter<'a> {
    layout: &'a str,
}

impl <'a> Formatter<'a> {
    pub fn new(layout: &'a mut &str) -> Formatter<'a> {
        let regex = Regex::new(r"%\{([a-z]+)(?::(.*?[^\\]))?\}").unwrap();
        *layout = regex.replace_all(layout, "{}");

        return Formatter {
            layout: layout,
        };
    }
}

This moves the problem one layer up the call stack and means that the reference you pass to new will be mutated by new.

pub fn main() {
    let mut s = "blah %{blah}";
    {
        let formatter = Formatter::new(&mut s);
        println!("{:?}", formatter.layout); // "blah {}"
    }
    println!("{:?}", s); // "blah {}"
}

Now s is owned by main, so formatter is valid as long as it is used only in a smaller scope than main.

But overall, I think this method is messier and you should just stick with String unless you have a good reason.

Share:
24,785

Related videos on Youtube

ๅฝญ็ตไฟŠ
Author by

ๅฝญ็ตไฟŠ

Updated on December 18, 2020

Comments

  • ๅฝญ็ตไฟŠ
    ๅฝญ็ตไฟŠ over 3 years

    I don't completely understand lifetimes, but I think b's lifetime will end before self's.

    So, how to edit this code? Do I copy something in memory? If I make a new instance, this lifetime must adhere to this case.

    pub struct Formater {
        layout: &'static str,
    }
    
    impl Formater {
        pub fn new(layout: &'static str) -> Formater {
            let regex = Regex::new(r"%\{([a-z]+)(?::(.*?[^\\]))?\}").unwrap();
            let b = regex.replace_all(layout, "{}");
    
            return Formater {
                layout: &b,
            };
        }
    }
    

    The error:

    error: `b` does not live long enough
      --> src/format.rs:16:22
       |
    16 |             layout: &b,
       |                      ^ does not live long enough
    17 |         };
    18 |     }
       |     - borrowed value only lives until here
       |
       = note: borrowed value must be valid for the static lifetime...
    
    • kennytm
      kennytm about 7 years
      You should make layout a String instead of &'static str. stackoverflow.com/questions/24158114/rust-string-versus-str
    • ๅฝญ็ตไฟŠ
      ๅฝญ็ตไฟŠ about 7 years
      thanks,this can help me do it.but,if i want use &str.how to do it?rust cannot direct edit lifetime๏ผŸ
    • wimh
      wimh about 7 years
      @ๅฝญ็ตไฟŠ why do you want to use &str?
    • Netwave
      Netwave about 7 years
      i dont get the part where the &' in Formater could be used with b since b is not a static str, you could not have a static reference to it right?
  • Lunfel
    Lunfel over 5 years
    layout: &'a mut &str. I don't quite understand how there can be two ampersands in the type signature. I quite new to Rust. Is one for burrow and the other a reference? Aren't burrows references? I am confused.
  • nuts-n-bits
    nuts-n-bits almost 3 years
    @Lunfel A reference is a borrow. This is a reference of a reference. So it is a borrow on the borrow. All checks out.