Rust - 从 `&str` 转换为 `String` 并返回闭包

Rust - Converting from `&str` to `String` and back with Closures

我正在研究 book,但我不明白为什么这个函数不能编译:

pub fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str> {
    contents
        .lines()                           // Fetch an iterator for each line in `contents`
        .map(|x| x.to_lowercase())         // (x is now String) Convert each line to lowercase
        .filter(|x| x.contains(query))     // Filter out lines that do not contain query
        .map(|x| x.trim())                 // Eliminate extra whitespace
        .collect()                         // Consume iterator and produce Vec<&str>
}

如果没有 to_lowercase() 行,它将 运行,我猜那是因为那将是 return 一个 String 而不是 &str我们需要在最后输出。但是,当我将转换替换回 &str 时,例如:

// -- snip --
.map(|x| x.to_lowercase().to_str())
// -- snip --

这表明正在引用一个临时值。我认为这是因为 &str 引用了 String,当 String 被释放时它也使我的 &str 无效。

闭包不是处理这个问题的好方法吗,我应该把它分成不同的语句吗?

This states that a temporary value is being referenced. Which I assume because &str reference the String, when the String is released it makes my &str invalid as well.

这个假设是正确的。

Are closures just not a good way of handling this, and I should break it into different statement?

该函数再多的重构也不会改变 to_lowercase() 需要修改 &str 并且必须生成 String 的事实,因此如果需要将内容小写化,那么这个是你能做的最好的:

fn search(query: &str, contents: &str) -> Vec<String> {
    contents
        .lines()                           // Fetch an iterator for each line in contents
        .map(|x| x.trim().to_lowercase())  // Trim & lowercase string
        .filter(|x| x.contains(query))     // Filter out lines that do not contain query
        .collect()                         // Consume iterator and produce Vec<String>
}

如果你想执行不区分大小写的过滤但仍然return未修改的内容(没有小写)那么你可以这样做:

fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str> {
    contents
        .lines()                                        // Fetch an iterator for each line in contents
        .filter(|x| x.to_lowercase().contains(query))   // Filter out lines that do not contain query
        .map(|x| x.trim())                              // Trim whitesapce
        .collect()                                      // Consume iterator and produce Vec<&'a str>
}

对于跟在我后面的人来说,这是我结束的地方。谢谢@pretzelhammer。

pub fn search_case_insensitive<'a>(query: &str, contents: &'a str) -> Vec<&'a str> {
    let query = query.to_lowercase(); // transform query to lowercase()
    contents
        .lines() 
        .filter(|x| x.to_lowercase().contains(&query))
        .map(|x| x.trim())
        .collect()
}