过滤Vec <String>时无法移出借用的内容

jdn*_*njd 2 types pointers lifetime dereference rust

我正在尝试实现一个函数,以将包含模式的所有字符串的向量从(Vec<String>)返回到另一个Vec<String>

这是我尝试的:

fn select_lines(pattern: &String, lines: &Vec<String>) -> Vec<String> {
    let mut selected_lines: Vec<String> = Vec::new();

    for line in *lines {
        if line.contains(pattern) {
            selected_lines.push(line);
        }
    }

    selected_lines
}
Run Code Online (Sandbox Code Playgroud)

导致在for循环的行上出现错误(*行)。我是Rust的新手(昨天开始学习Rust!),现在对解决该错误几乎一无所知。

我可以删除,*并且该错误消失了,但是有关类型不匹配的错误开始达到高潮。我想保持功能的签名完整。有办法吗?

Sim*_*ead 5

问题是,你想移动的所有权String情况下出去您的lines参数(这是一个输入参数)...过户到返回值(输出)。

有几个选项供您选择。

选项1 - Clone

对您来说最简单的方法就是将这些行克隆出来:

selected_lines.push(line.clone());
Run Code Online (Sandbox Code Playgroud)

既然您已经克隆了行,那么就没有所有权问题了。您要返回的是向量中s的新实例String。它们只是您传递的副本的副本。

选项2- 生命周期

另一个选择(避免多余的分配)是让编译器知道您将不返回任何悬空的引用:

// introduce a lifetime to let the compiler know what you're
// trying to do. This lifetime basically says "the Strings I'm returning
// in the vector live for at least as long as the Strings coming in
fn select_lines<'a>(pattern: &String, lines: &'a Vec<String>) -> Vec<&'a String> { 
    let mut selected_lines: Vec<&String> = Vec::new();

    for line in lines {
        if line.contains(pattern) {
            selected_lines.push(line);
        }
    }

    selected_lines
}
Run Code Online (Sandbox Code Playgroud)

这就是解决当前问题的方法。

另一个旋转

如果我要写这个,我会稍作修改。这是另一个旋转:

fn select_lines<I>(pattern: I, lines: &[I]) -> Vec<&str>
where
    I: AsRef<str>,
{
    let mut selected_lines: Vec<&str> = Vec::new();

    for line in lines {
        if line.as_ref().contains(pattern.as_ref()) {
            selected_lines.push(line.as_ref());
        }
    }

    selected_lines
}
Run Code Online (Sandbox Code Playgroud)

您可以将此版本与Strings或&strs,向量或切片一起使用。

let lines = vec!["Hello", "Stack", "overflow"];

let selected = select_lines("over", &lines);

// prints "overflow"
for l in selected {
    println!("Line: {}", l);
}

let lines2 = [String::from("Hello"), String::from("Stack"), "overflow".into()];

let selected2 = select_lines(String::from("He"), &lines2);

// prints "Hello"
for l in selected2 {
    println!("Line again: {}", l);
}
Run Code Online (Sandbox Code Playgroud)

它在操场上跑