I'm sorry, it's probably was answered a lot of times, but I can't google it for some reason. Here's what I'm trying to do.
struct S<'a>(&'a str);
impl<'a> S<'a> {
fn new() -> Self {
let s = format!("foo");
S(&s) // returns a value referencing data owned by the current function
}
}
I understand that as new owns s it's borrow can't be returned. It would work with a static string if I remove format!, but what to do if the string should be generated at runtime?
If you want to generate the string dynamically inside the constructor, then you simply can't return a reference to it. There is no way around that. If you have a dynamically-formatted String to begin with, you can just store that by value inside S.
As you've surmised, the compiler is complaining because the s variable is only alive inside the S::new() constructor, but we need to make sure it lives for longer so the resulting S can be useful.
The solution is to make sure either a) S owns the string instead of giving it a reference, or b) the string comes from outside of the function so that S won't outlive it.
struct S<'a>(&'a str);
impl<'a> S<'a> {
fn new(text: &'a str) -> Self { S(text) }
}
fn main() {
// create a string which is alive for the duration of main()
let some_string = format!("foo");
// Note: `s` is not allowed to outlive `some_string`
let s = S::new(&some_string);
}
If you are generating the strings at runtime you'll use the first solution 99% of the time.
Given the signature fn new() -> Self, you may want to instead implement the Default trait. It's the canonical way to define a default constructor, and other code can compose well with the trait. You can often derive the implementation, as noted in the documentation (but not when you have a reference in your struct).
If you're sure you want to store &str, and you still want a default constructor (Default implementation), you could do something like:
impl Default for S<'static> {
fn default() -> Self {
// The literal string "foo" lives for the entire
// lifetime of the program ('static)
S("foo")
}
}
(If you're not sure that you need &str, you probably want to go with String, as the others noted.)