I'm working through the book and I'm not understanding why this function doesn't compile:
pub fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str> {
contents
.lines() // Fetch an iterator for each line in `contents`
.map(|x| x.to_lowercase()) // (x is now String) Convert each line to lowercase
.filter(|x| x.contains(query)) // Filter out lines that do not contain query
.map(|x| x.trim()) // Eliminate extra whitespace
.collect() // Consume iterator and produce Vec<&str>
}
Without the to_lowercase()
line it will run, and I'm guessing that is because that will return a String
instead of the &str
we'll need to output at the end. However when I either substitute a conversion back to &str
like:
// -- snip --
.map(|x| x.to_lowercase().to_str())
// -- snip --
This states that a temporary value is being referenced. Which I assume because &str
reference the String
, when the String
is released it makes my &str
invalid as well.
Are closures just not a good way of handling this, and I should break it into different statement?
This states that a temporary value is being referenced. Which I assume because
&str
reference theString
, when theString
is released it makes my&str
invalid as well.
This assumption is correct.
Are closures just not a good way of handling this, and I should break it into different statement?
No amount of refactoring that function will change the fact that to_lowercase()
requires modifying the &str
and has to produce a String
, so if lowercasing the contents is a requirement then this is the best you can do:
fn search(query: &str, contents: &str) -> Vec<String> {
contents
.lines() // Fetch an iterator for each line in contents
.map(|x| x.trim().to_lowercase()) // Trim & lowercase string
.filter(|x| x.contains(query)) // Filter out lines that do not contain query
.collect() // Consume iterator and produce Vec<String>
}
If you want to perform case-insensitive filtering but still return the unmodified contents (no lowercasing) then you can do this:
fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str> {
contents
.lines() // Fetch an iterator for each line in contents
.filter(|x| x.to_lowercase().contains(query)) // Filter out lines that do not contain query
.map(|x| x.trim()) // Trim whitesapce
.collect() // Consume iterator and produce Vec<&'a str>
}