The reason you can’t do this is because bindings (variables) that you define in a function only live for as long as the function is executing. This isn’t specifically a Rust semantic but really a more general semantic of how (most or all?) modern computers work. When a function is called, a block of memory is created for that function to store temporary data in, called “a function stack.” When that function finishes, this function stack is, for all intents and purposes, “destroyed” by the operating system, invalidating whatever was contained within it so that the memory can be reused by other functions in the future.
In order to return a value (indeed, any value) from a function, it has to be either copied to a memory location that the function’s caller has access to, or placed in a special memory location called “the heap,” which is one particular place that each of your functions has access to and isn’t destroyed the same way that a function stack is.
You thus have two possible solutions:
- Pass a mutable reference as an argument to your function and use that to copy the value you want to create into the caller’s memory space.
- Store the data you created on the heap, so that you can return a reference to that location instead.
The easier way, in my opinion, though certainly slightly less efficient (for reasons you probably don’t need to worry about right now) is to go with option 2 and store your string on the heap. Fortunately, Rust makes this easy with the String
type. You can copy a &str
onto the heap and get a String
as a result by simply calling the to_owned()
method on a &str
. Your example code could thus be rewritten to:
fn main() {
println!("I can show you {}", what04());
}
fn what04<'a>() -> String {
let mut what = "the".to_string();
what.push_str(" world. - 4.");
what.split_at(what.len()).0.to_owned()
}
Now the return value of what04
is no longer a &str
, but you can actually tell Rust to treat it like one by taking a borrowed reference to your string.
Hope this helps.