Sunday, July 10, 2022

[FIXED] why should this be borrowed?

Issue

From The Book, listing 13-29:

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

After an explanation of the above, the reader is invited, "Feel free to make the same change to use iterator methods in the search_case_insensitive function as well." Don't mind if I do:

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

Nope:

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()))
    |                                                     +

Indeed, this compiles and passes the tests from the earlier examples:

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

For that matter, search will compile and pass if query is borrowed:

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

So why must query be borrowed in search_case_insensitive but its being a reference (or not) makes no difference to search?


Solution

The method str::contains() takes as a predicate generic P: Pattern. The Pattern trait is implemented for char, &char, &String, &[char], &str, &&str, [char; N], &[char; N] and F where F: FnMut(char) -> bool. All of those can be passed to contains(). However, it is not implemented for String. So in search(), you pass &str. That's fine. If you borrow it, you pass &&str, which is also fine. But in search_case_insensitive(), if you borrow you pass &String and that's fine, but if you don't, you pass String which does not implement the Pattern trait.



Answered By - Chayim Friedman
Answer Checked By - Terry (PHPFixing Volunteer)

No comments:

Post a Comment

Note: Only a member of this blog may post a comment.