将 Vec<u64> 转换为 Vec<(&str, u64)> for tui::BarChart data



我怎样才能把Vec<u64>变成Vec<(&str, u64)>,这样 前者的索引嵌入到后者的str部分?

例如,[4, 9, 3]应该变成[("0", 4), ("1", 9), ("2", 3)]

我想这样做的原因是因为我想绘制我的 矢量使用 TUI 中的条形图,这需要这样的类型。

我已经尝试了一些明显的事情,例如循环和推送:

fn main() {
let my_vec: Vec<u64> = vec![4, 9, 3];
let mut result: Vec<(&str, u64)> = Vec::new();
for (k, v) in my_vec.iter().enumerate() {
result.push((&k.to_string(), *v));
}
assert_eq!(result, [("0", 4), ("1", 9), ("2", 3)]);
}
error[E0716]: temporary value dropped while borrowed
--> src/main.rs:5:23
|
5 |         result.push((&k.to_string(), *v));
|                       ^^^^^^^^^^^^^      - temporary value is freed at the end of this statement
|                       |
|                       creates a temporary which is freed while still in use
...
8 |     assert_eq!(result, [("0", 4), ("1", 9), ("2", 3)]);
|     --------------------------------------------------- borrow later used here
|
= note: consider using a `let` binding to create a longer lived value

或使用map

fn main() {
let my_vec: Vec<u64> = vec![4, 9, 3];
let result: Vec<(&str, u64)> = my_vec
.into_iter()
.enumerate()
.map(|(k, v)| (&k.to_string(), v))
.collect();
assert_eq!(result, [("0", 4), ("1", 9), ("2", 3)]);
}
error[E0277]: a value of type `std::vec::Vec<(&str, u64)>` cannot be built from an iterator over elements of type `(&std::string::String, u64)`
--> src/main.rs:7:10
|
7 |         .collect();
|          ^^^^^^^ value of type `std::vec::Vec<(&str, u64)>` cannot be built from `std::iter::Iterator<Item=(&std::string::String, u64)>`
|
= help: the trait `std::iter::FromIterator<(&std::string::String, u64)>` is not implemented for `std::vec::Vec<(&str, u64)>`

但无论我做什么,我似乎都无法绕过终身问题, 因为k.to_string()活得不够长。

当然,如果有更好的方法来获取向量,我愿意接受建议 以其索引作为标签绘制。

你不能直接这样做,&str借用字符串,这样字符串在你借用它们时必须保持活动状态,一般的答案是创建你的字符串,储存它们并借用它们,例如:

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)]);
}

虽然这将适用于您的具体情况data()但很奇怪。如果不挖掘更多,很难判断是否有问题。在您链接的示例中,str是静态的,可能它只是(或主要(打算像示例一样使用,因此您不需要将其与动态索引一起使用。

&str引用必须指向比result寿命更长的字符串。不能使用对临时字符串的引用,因为它们会过早删除。

一种选择是将所有String存储在一个比result寿命更长的集合中。预先计算它们,然后存储对这些长期字符串的引用:

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();

(游乐场(

这可能只会将您的问题提升一个级别。您可能没有一个好地方来存放String,以便它们活得足够长。如果您希望它们在当前函数调用之后存活,则它们不能位于堆栈上的局部变量中。

第二种选择是将Strings转换为Box<str>,然后用Box::leak泄漏内存。泄露的参考文献永远存在,因此可以被视为'static

注意不要滥用这种技术,只是为了让编译器在抱怨生命周期时关闭它。只有当字符串永远存在确实有意义时,您才应该这样做。如果标签将在应用程序运行的整个过程中显示,则没关系。如果它们位于已关闭或以其他方式消失的 UI 元素中,请不要这样做。

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();

(游乐场(

最新更新