I am trying to use a map-like function from an external library that essentially has the following shape:
fn map_like<'a, F>(nums: &[usize], f: F) -> Vec<&'a [u8]>
where
F: Fn(usize) -> &'a [u8],
{
nums.iter().map(|num| f(*num)).collect()
}
I also have a constant lookup "table":
const NAMES: [&str; 4] = ["Ada", "Hal", "Max", "Val"];
and a previously generated array of indices for looking up items in the table:
let indices: &[usize] = &[0, 3, 1, 2];
I want to use the map-like function to generate an array of "greetings" (as bytes) from the lookup table and the indices.
I can generate the following trivial "greetings":
let greetings: Vec<&[u8]> = map_like(indices, &|i| {
let name: &str = NAMES[i];
let greeting: &str = name;
greeting.as_bytes()
});
// Prints `[[65, 100, 97], [86, 97, 108], [72, 97, 108], [77, 97, 120]]`
println!("{:?}", greetings);
But what I really want to do is format a larger greeting out of each name:
// Does not compile
let greetings: Vec<&[u8]> = map_like(indices, &|i| {
let name: &str = NAMES[i];
let greeting: String = format!("Hello, {}!", name);
greeting.as_bytes()
});
Unfortunately, the compiler doesn't allow this. It throws the following error:
error[E0515]: cannot return reference to local variable `greeting`
--> src/main.rs:10:9
|
10 | greeting.as_bytes()
| ^^^^^^^^^^^^^^^^^^^ returns a reference to data owned by the current function
I believe that I even understand what is happening: the format!
macro is creating a new String
that's local to the closure, which as_bytes
in turn creates a reference to. Since this new string is deallocated at the end of the closure, this would result in a dangling reference, which the compiler won't allow.
Even so, I am at a loss for a workaround. I can't come up with a reasonable method for constructing a larger greeting from each name that the compiler is happy with. What is an idiomatic Rust way of approaching this?