Help with adding iterators to `search_case_insensitive` from the book

TLDR:
Is it possible to make an iterator version of the search_case_insensitive function from the rust book? Is that even a smart thing to do in this case?

Long Version:
I'm working on chapter 12 of the rust book, and wanted to try my hand at editing the search function.

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
}

The book mentions shorty after "At this point, we could consider opportunities for refactoring the implementation of the search function while keeping the tests passing to maintain the same functionality. The code in the search function isn’t too bad, but it doesn’t take advantage of some useful features of iterators. We’ll return to this example in [Chapter 13][ch13], where we’ll explore iterators in detail, and look at how to improve it."
So I tried my hand at implementing an iterator, and it seems to be working well.

pub fn my_search<'a>(query: &str, contents: &'a str) -> Vec<&'a str> {
    let results = contents.lines()
        .filter(|x| x.contains(query))
        .collect();

    results
}

After creating the search function, we also implement a search_case_insensitive function. In the book this is written as

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

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

    results
}

I wanted to try implementing a version of this with iterators as well. Here's what I wrote

pub fn my_search_case_insensitive<'a>(query: &str, contents: &'a str) -> Vec<&'a str> {
    let query = query.to_lowercase();
    let results = contents.lines()
        .map(|x| x.to_lowercase())
        .filter(|x| x.contains(&query))
        .collect();
    results
}

This does not, of course, compile. I think because when the x.to_lowercase() is applied, the output is now a String, instead of a str. Hence, when collect() is called I get the error

a collection of type `std::vec::Vec<&str>` cannot be built from `std::iter::Iterator<Item=std::string::String>`

with respect to the collect() call.

I think the original does compile, because line is being pushed onto the vector, but line itself is not modified by the call if line.to_lowercase().contains(&query) hence each line item is a &str.

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.