如何在使用iter().filter().collect()后得到Vec<&String>而不是Vec<&&String>

6

我有一个字符串向量。我想从这个向量中获取两个子集:包含 "zzz" 的字符串和包含 "bye" 的字符串。

每个子集的类型是 Vec< && String>,即对原始字符串引用的引用向量。如何只获取 Vec<& String>

我目前正在处理的代码:

use std::string::String;
use std::vec::Vec;

fn main() {
    let a1 = String::from("hi");
    let a2 = String::from("bye");
    let a3 = String::from("zzz");

    let v_before: Vec<&String> = vec![&a1, &a2, &a3];

    // ref_a is a copy of v_before[0]
    let ref_zzz_a: &String = v_before[2];
    let ref_zzz_b: &String = v_before[2];

    println!("before: {:?}", v_before);

    // QUESTION: why can not this also be Vec<& String> ?
    // v_zzz is just like making  vec![ref_zzz_a, ref_zzz_b]
    let v_zzz: Vec<&&String> = v_before
        .iter()
        .filter(|&&element| element.contains("zzz"))
        .collect();

    let v_bye: Vec<&&String> = v_before
        .iter()
        .filter(|&&element| element.contains("bye"))
        .collect();

    let hand_made: Vec<&String> = vec![ref_zzz_a, ref_zzz_b];

    println!("v_zzz: {:?}", v_zzz);
    println!("v_bye: {:?}", v_bye);
    println!("hand_made: {:?}", hand_made);
}

(Playground)
一种方法是使用vector.into_iter()...,但这样我就无法运行第二个过滤器。
另外也许这就是Rust的方式?由于自动解引用,也许我应该不关心这是一个Vec<&& String>?这会导致以后出现问题吗?
1个回答

11

您可以使用Iterator::cloned方法来克隆每个引用,而不是再次引用它们:

let v_zzz: Vec<&String> = v_before
    .iter()
    .filter(|&element| element.contains("zzz"))
    .cloned()
    .collect();

克隆引用是廉价的,因为它通过解引用实现


顺带一提:通常更好的方式是传递&str而不是&String,因为它更灵活。当我在Rust代码中看到&String时,它会突出显示为可能不被意图,或者可以改进的东西。


谢谢!考虑在.filter()后加上.cloned(),因为可能存在这种情况:https://dev59.com/PZTfa4cB1Zd3GeqPKgG9 - user10607
@user10607 是的!在看到你的评论之前,我刚刚发现并更改了那个问题。不过,在这种情况下,我不确定它是否有太大的影响,因为只是一个指针被克隆了。 - Peter Hall
1
@user10607,但是也请查看该问题的第二个答案,因为它同样适用于这里(因为指针很小且可复制)。 - Peter Hall

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接