为什么要借这个?

why should this be borrowed?

来自本书,listing 13-29

pub fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str> {
    contents
        .lines()
        .filter(|line| line.contains(query))
        .collect()
}

在对上述内容进行解释后,邀请 reader,“请随意进行相同的更改以在 search_case_insensitive 函数中使用迭代器方法。”不要介意我这样做:

pub fn search_case_insensitive<'a>(query: &str, contents: &'a str) -> Vec<&'a str> {
    contents
        .lines()
        .filter(|line| line.to_lowercase().contains(query.to_lowercase()))
        .collect()
}

没有:

error[E0277]: expected a `FnMut<(char,)>` closure, found `String`
   --> src/lib.rs:59:53
    |
59  |         .filter(|line| line.to_lowercase().contains(query.to_lowercase()))
    |                                            -------- ^^^^^^^^^^^^^^^^^^^^ expected an implementor of trait `Pattern<'_>`
    |                                            |
    |                                            required by a bound introduced by this call
    |
    = note: the trait bound `String: Pattern<'_>` is not satisfied
    = note: required because of the requirements on the impl of `Pattern<'_>` for `String`
note: required by a bound in `core::str::<impl str>::contains`
help: consider borrowing here
    |
59  |         .filter(|line| line.to_lowercase().contains(&query.to_lowercase()))
    |                                                     +

确实,这编译并通过了前面示例中的测试:

pub fn search_case_insensitive<'a>(query: &str, contents: &'a str) -> Vec<&'a str> {
    contents
        .lines()
        .filter(|line| line.to_lowercase().contains(&query.to_lowercase()))
        .collect()
}

就此而言,如果 query 被借用,search 将编译并通过:

pub fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str> {
    contents
        .lines()
        .filter(|line| line.contains(&query))
        .collect()
}

那么为什么 query 必须在 search_case_insensitive 中借用,但它是(或不是)引用对 search 没有影响?

contains() 方法需要某种实现 Pattern 特性的类型作为输入。此特征是为 &str 实现的,而不是 String。这意味着 contains() 可以与 &str 一起使用,但不能与 String 一起使用(至少不能直接使用)。

对于 line.contains(query) 的情况,query 已经是 &str,所以我们很好。

query.to_lowercase() returns 一个 String 类型,所以它不编译。但是,String 可以通过借用变成 &str,这就是 &query.to_lowercase() 起作用的原因。

方法 str::contains() takes as a predicate generic P: Pattern. The Pattern trait 已为 char&char&String&[char]&str&&str 实现、[char; N]&[char; N]F where F: FnMut(char) -> bool。所有这些都可以传递给 contains()。但是,它没有为 String 实现。所以在 search() 中,你传递了 &str。没关系。借了就传&&str,也行。但是在 search_case_insensitive() 中,如果你借用你传递 &String 这很好,但如果你不借用,你传递 String 没有实现 Pattern 特性。