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
.