我怎样才能把 aVec<u64>变成 a 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)]);
}
Run Code Online (Sandbox Code Playgroud)
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
Run Code Online (Sandbox Code Playgroud)
或使用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)]);
}
Run Code Online (Sandbox Code Playgroud)
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)>`
Run Code Online (Sandbox Code Playgroud)
但无论我做什么,我似乎都无法解决终身问题,因为k.to_string()活得不够长。
当然,如果有更好的方法来绘制向量及其索引作为标签,我愿意接受建议。
Sta*_*eur 13
你不能直接做到这一点,&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)]);
}
Run Code Online (Sandbox Code Playgroud)
虽然这适用于您的特定情况data()很奇怪。如果不深入挖掘,很难判断是否有问题。在您链接的示例中,str静态的可能只是(或主要)打算像示例一样使用,因此您不应将其与动态索引一起使用。
该&str引用必须指向字符串会活得比result。您不能使用对临时字符串的引用,因为它们被删除得太快了。
一种选择是将所有Strings存储在一个寿命更长的集合中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();
Run Code Online (Sandbox Code Playgroud)
(游乐场)
这可能只会将您的问题提升一个层次。您可能没有一个很好的地方来存放Strings,这样它们就可以存活足够长的时间。如果您希望它们比当前函数调用更有效,它们就不能位于堆栈上的局部变量中。
第二个选择是将转换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();
Run Code Online (Sandbox Code Playgroud)
(游乐场)
| 归档时间: |
|
| 查看次数: |
326 次 |
| 最近记录: |