如何传递修改后的字符串参数?

How do I pass modified string parameters?

我在 chapter 12 of The Rust Programming Language,其中实现了不区分大小写的行搜索。两次实现相同的逻辑对我来说没有意义,所以我想如果我只是调用区分大小写的搜索函数并将参数转换为小写,那可能会起作用。它没有。

这是我的非工作代码:

fn main() {
    let a = search("Waldo", "where in\nthe world\nis Waldo?");
    let b = search("waldo", "where in\nthe world\nis Waldo?");
    let c = search_case_insensitive("waldo", "where in\nthe world\nis Waldo?");

    println!("{:?}", a);
    println!("{:?}", b);
    println!("{:?}", c);
}

pub fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str> {
    let mut results = Vec::new();

    for line in contents.lines() {
        if line.contains(query) {
            results.push(line);
        }
    }

    results
}

pub fn search_case_insensitive<'a>(query: &str, contents: &'a str) -> Vec<&'a str> {
    let query = query.to_lowercase();
    let contents2: &str = &contents.to_lowercase();

    search(&query, contents2)
}

我想出的大多数版本中的错误不可避免地非常类似于:

error[E0597]: borrowed value does not live long enough
  --> src/main.rs:25:28
   |
25 |     let contents2: &str = &contents.to_lowercase();
   |                            ^^^^^^^^^^^^^^^^^^^^^^^ temporary value does not live long enough
...
28 | }
   | - temporary value only lives until here
   |
note: borrowed value must be valid for the lifetime 'a as defined on the function body at 23:1...
  --> src/main.rs:23:1
   |
23 | pub fn search_case_insensitive<'a>(query: &str, contents: &'a str) -> Vec<&'a str> {
   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

您对变量的生命周期引入了不可能的约束 contents2;通过编写 &'a,您试图为其分配与 contents 参数相同的生命周期,但它是在 search_case_insensitive 范围内创建和销毁的,因此比 contents.

为了 contents2search_case_insensitive 的主体更长久,您需要将其 return 作为 String 并分配给它之外的某个变量,或者只要它在其他地方已经作为 String 存在,就可以通过引用将其传递给 search_case_insensitive

引用 The Book:

It's important to understand that lifetime annotations are descriptive, not prescriptive. This means that how long a reference is valid is determined by the code, not by the annotations.

编辑 2:

因为你已经用 MCVE 更新了问题并且你已经声明你不关心偏离书中的例子......这是另一个版本依赖于通过使用 [=14 进行额外分配=]:

fn main() {
    let a = search("Waldo", "where in\nthe world\nis Waldo?");
    let b = search("waldo", "where in\nthe world\nis Waldo?");
    let c = search_case_insensitive("waldo", "where in\nthe world\nis Waldo?");

    println!("{:?}", a);
    println!("{:?}", b);
    println!("{:?}", c);
}

pub fn search<S>(query: S, contents: S) -> Vec<String> where S: Into<String> {
    let query = query.into();
    let mut results = Vec::new();

    for line in contents.into().lines() {
        if line.contains(&query) {
            results.push(line.into());
        }
    }

    results

}

pub fn search_case_insensitive<S>(query: S, contents: S) -> Vec<String> where S: Into<String> {
    let query = query.into().to_lowercase();
    let contents = contents.into().to_lowercase();

    search(query, contents)
}

这里是running in the Playground

编辑:

我意识到我从来没有真正给过你一个选择。这是我可能会做的:

pub enum SearchOptions {
    CaseSensitive,
    CaseInsensitive
}

pub fn search<'a>(query: &str, contents: &'a str, options: SearchOptions) -> Vec<&'a str> {
    let mut results = Vec::new();

    for line in contents.lines() {
        let check = match options {
            SearchOptions::CaseSensitive => line.contains(query),   
            SearchOptions::CaseInsensitive => line.to_lowercase().contains(&query.to_lowercase()),   
        };
    
        if check {
            results.push(line);
        }
    }

    results
}

这就是您可以对其进行“去重”的最大程度。

原回答:

实际的问题是,当 contents 绑定到生命周期 'a 时,您试图传递 contents ...但是您真正想要“不区分大小写”的是query.

这并没有以完全相同的方式绑定到生命周期 'a,因此......有效:

pub fn search_case_insensitive<'a>(query: &str, contents: &'a str) -> Vec<&'a str> {
    let query = query.to_lowercase();
    search(&query, contents)
}

Here it is on the playground

你仍然需要复制逻辑......因为你需要将小写查询与小写行相匹配......这在书中的示例中得到了证明:

if line.to_lowercase().contains(&query) {
//      ^^^^^^^^^^^^^^ each LINE is converted to lowercase here in the insensitive search
    results.push(line);
}

“如何停止重复逻辑?” - 嗯,他们一开始就不完全一样。我认为您的尝试并不完全是您最初想要的(不过很高兴得到纠正)。