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...
These word references cannot outlive the if let block, which means you cannot use them as keys in the hash map. The easiest fix is to have words_matches own its keys. Without borrows there are no lifetimes, and thus no lifetime issues.
A static is never "inlined" at the usage site, and all references to it refer to the same memory location. Static items have the static lifetime, which outlives all other lifetimes in a Rust program. Static items may be placed in read-only memory if the type is not interior mutable.
7 months ago. by John Otieno. A static variable refers to a type of variable that has a fixed memory location. They are similar to constant variables except they represent a memory location in the program.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With