如何将Vec<u64>
变成Vec<(&str, u64)>
,例如
前者的索引已嵌入后者的str
部分中?
例如,[4, 9, 3]
应该变成[("0", 4), ("1", 9), ("2", 3)]
。
我要这样做的原因是因为我想绘制我的条形图 使用the barchart from 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()
的寿命不足。
当然,如果有更好的方法来获取矢量,我愿意提出建议 以其索引作为标签进行绘制。
答案 0 :(得分:13)
您不能直接这样做,&str
借用字符串,因此在借用字符串时字符串必须保持活动状态,通常的答案是创建,存储和借用字符串,例如:< / p>
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
是静态的,也许仅(或主要)打算像示例一样使用,因此不希望将其与动态索引一起使用。
答案 1 :(得分:8)
&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
的地方,因为它们的寿命足够长。如果您希望它们在当前函数调用之前不存在,则它们不能位于堆栈的局部变量中。
第二种选择是将String
转换为Box<str>
,然后将leak the memory转换为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();