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

时间:2018-07-04 06:10:31

标签: string rust borrow-checker

我在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> {
   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

2 个答案:

答案 0 :(得分:1)

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

为了使contents超出contents2的主体,您需要将其作为search_case_insensitive返回并分配给它之外的某个变量或将其传递给{{1 }},只要它已经在其他地方的String中存在。

引用The Book

  

重要的是要了解终身注释是   描述性而非说明性。这意味着参考多长时间   是否有效取决于代码,而不取决于注释。

答案 1 :(得分:1)

编辑2:

由于您已经使用MCVE更新了问题,并且已经声明您不担心会偏离本书的示例,所以这是另一个依靠String进行额外分配的版本:

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时,正在尝试通过它,但是您真正想成为“不区分大小写”的是{{ 1}}。

这与生存期query并没有完全相同的方式,因此……有效:

'a

Here it is on the playground

尽管如此,您仍然需要重复逻辑……因为您需要将小写查询与小写行匹配……这在本书的示例中得到了证明:

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

“如何停止重复逻辑?” -嗯,它们起初并不完全相同。我认为您的尝试与最初的尝试并不完全相同(不过很高兴得到纠正)。