首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >将Vec<u64>转换为Vec<(&str,u64)>用于tui::条形图数据

将Vec<u64>转换为Vec<(&str,u64)>用于tui::条形图数据
EN

Stack Overflow用户
提问于 2020-05-23 21:52:47
回答 2查看 427关注 0票数 17

如何将Vec<u64>转换为Vec<(&str, u64)>,使前者的索引嵌入到后者的str部分中?

例如,应该将[4, 9, 3]转换为[("0", 4), ("1", 9), ("2", 3)]

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

我尝试过一些显而易见的事情,比如循环和推:

代码语言:javascript
复制
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)]);
}
代码语言:javascript
复制
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

代码语言:javascript
复制
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)]);
}
代码语言:javascript
复制
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()的寿命不够长。

当然,如果有更好的方法用它的索引作为标签来绘制向量,我会给出一些建议。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2020-05-23 22:25:13

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

代码语言:javascript
复制
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是静态的--可能它只是(或者主要)打算像示例那样使用,因此您不需要在动态索引中使用它。

票数 13
EN

Stack Overflow用户

发布于 2020-05-23 22:34:39

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

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

代码语言:javascript
复制
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>,然后将漏出内存Box::leak进行转换。泄漏的引用永远存在,因此可以被视为'static

注意不要滥用这种技术,这只是为了在编译器抱怨生命周期时关闭编译器。只有当字符串永远存在的时候,你才应该这样做。如果在应用程序运行的整个过程中都会显示标签,那么就可以了。如果它们将在关闭或以其他方式消失的UI元素中,请不要这样做。

代码语言:javascript
复制
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();

(游乐场)

票数 8
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/61979023

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档