Turn Vec<u64> into Vec<(&str, u64)> for tui::BarChart data

You can't do it directly, &str borrow the string so the string must stay alive while you borrow them, the general answer is to create your string, stock them and borrow them, like for example:

fn main() {
    let my_vec: Vec<u64> = vec![4, 9, 3];

    let my_owned : Vec<(String, u64)> = my_vec
        .into_iter()
        .enumerate()
        .map(|(k, v)| (k.to_string(), v))
        .collect();

    let result: Vec<(&str, u64)> = my_owned
        .iter()
        .map(|(k, v)| (k.as_str(), *v))
        .collect();

    assert_eq!(result, [("0", 4), ("1", 9), ("2", 3)]);
}

While this will work on your specific case data() is strange. Without digging more it's hard to tell if there is something wrong. In the example you linked, the str are static maybe it's only(or mainly) intended to be use like the example, and so you are not expected to use it with dynamic index.


The &str references have to point to strings that will outlive result. You can't use references to temporary strings as they're dropped too soon.

One option is to store all the Strings in a collection that outlives result. Precompute them and then store references to those long-lived strings:

let my_vec: Vec<u64> = vec![4, 3, 9];
let labels: Vec<String> = (0..my_vec.len())
    .map(|i| i.to_string())
    .collect();

let result: Vec<_> = labels.iter()
    .zip(my_vec)
    .map(|(k, v)| (k.as_str(), v))
    .collect();

(Playground)

That may just push your problem up a level. You may not have a good place to store Strings such that they live long enough. They can't be in a local variable on the stack if you intend them to outlive the current function call.

A second option is to convert the Strings to Box<str> and then leak the memory with Box::leak. Leaked references live forever and therefore can be treated as 'static.

Be careful not to abuse this technique just to shut the compiler up when it complains about lifetimes. You should only do it if it really does make sense for the strings to live forever. If the labels will be displayed the entire time your application runs then it's fine. Don't do it if they'll be in a UI element that is closed or otherwise disappears.

let my_vec: Vec<u64> = vec![4, 3, 9];

let result: Vec<(&str, u64)> = my_vec.iter()
    .enumerate()
    .map(|(k, v)| (Box::leak(k.to_string().into_boxed_str()) as &str, *v))
    .collect();

(Playground)

Tags:

Rust