为什么应该借用这个?

3

摘自《Rust编程语言》第13章第3节代码清单 13-29

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

在上述内容的解释之后,读者被邀请“随意对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()
}

那么为什么search_case_insensitive函数必须借用query参数,但对于search函数来说,它是一个引用还是不是引用都没有影响呢?

2个回答

3

方法str::contains()以泛型P: Pattern作为谓词。Pattern特性适用于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,这很好,但如果你不这样做,你就传递了没有实现Pattern特性的String


谢谢,Chayim。我不明白为什么在错误的示例中,query在函数体中是一个String,而在签名中声明为query: &str - Franklin Einspruch
3
因为你传递的不是query而是query.to_lowercase(),并且str::to_lowercase()返回的是String - Chayim Friedman

2
contains() 方法需要输入实现 Pattern 特质的某种类型。该特质已为 &str 实现,但尚未为 String 实现。这意味着可以使用 contains() 来查找 &str,但不能直接用于 String
对于 line.contains(query) 情况,query 已经是一个 &str,所以没问题。 query.to_lowercase() 返回的是 String 类型,因此无法编译。然而,String 可以通过借用转换为 &str,这就是为什么 &query.to_lowercase() 能够工作的原因。

至于为什么 line.contains(&query) 起作用...不太确定。&query 可以编译,但 &&query 不行。这可能是一个很好的单独问题!我尝试搜索了一下,但只得到了关于“多个借用”的错误结果。 - effect
2
@ChayimFriedman解释了为什么&&query有效,以及为什么Pattern被实现为&&str - effect

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接