【问题标题】:Rust - Converting from `&str` to `String` and back with ClosuresRust - 从 `&str` 转换为 `String` 并使用闭包返回
【发布时间】:2021-04-30 12:27:15
【问题描述】:

我正在处理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() 行,它将运行,我猜这是因为这将返回String 而不是&amp;str,我们需要在最后输出。但是,当我将转换替换回 &amp;str 时,例如:

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

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

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

【问题讨论】:

  • 最终结果是否需要小写?还是只需要查询匹配?
  • 哦,这很好。在我的情况下,我想单独留下内容,并将其用于查询匹配。不过,我会对任一方向的答案感兴趣。

标签: rust closures borrow-checker ownership borrowing


【解决方案1】:

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

这个假设是正确的。

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

对该函数进行再多的重构都不会改变to_lowercase() 需要修改&amp;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>
}

如果您想执行不区分大小写的过滤但仍返回未修改的内容(不小写),那么您可以这样做:

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>
}

【讨论】:

  • 有趣,所以要么a)切换到vec&lt;String&gt;,因为我需要修改内容(例如小写)或b)链小写()和包含()将返回一个布尔而不是引用立即被释放的字符串。
  • 需要生命周期,因为 Vec 只有在内容仍然存在时才有效。
  • @Gates 是的,你明白了!
【解决方案2】:

对于跟在我身后的人,这就是我的结局。谢谢@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()
}

【讨论】:

    猜你喜欢
    • 2017-05-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-09-23
    • 2013-03-01
    • 1970-01-01
    • 2017-11-16
    相关资源
    最近更新 更多