Question about Iterators, Closures, Borrowing, and Lifetime
⚓ Rust 📅 2025-10-01 👤 surdeus 👁️ 7I'm working through the rust book and I'm on chapter regarding closures. I'm refactoring the minigrep code with what I've learned and ran into a compilation issue that I don't understand.
// Fails with "error[E0373]: closure may outlive the current function, but it borrows `query`, which is owned by the current function"
pub fn search_iter<'a>(
    query: &str,
    contents: &'a str
) -> impl Iterator<Item = &'a str> {
    contents
        .lines()
        .filter(|line| line.contains(&query))
        //      ^^^^^ add a move before this to fix
}
However, this builds fine:
pub fn search_case_insensitive_iter<'a>(
    query: &str,
    contents: &'a str
) -> impl Iterator<Item = &'a str> {
    contents
        .lines()
        .filter(|line| line.to_lowercase().contains(&query.to_lowercase()))
}
I understand that query.to_lowercase() will return a string, but I don't understand how that changes things.
My understanding is as follows:
- "query" is passed in as a &str, and is therefore a reference (string slice reference).
- By default, closures capture by reference. Adding move will cause the closure to take ownership of the captured item.
- Iterators are lazy, so the filter isn't even executed at the time a caller invokes either of these functions, but while iterating over data afterward.
If query is a string reference, why does adding "move" do anything? The closure outlives the "search" function, but it also outlives it in the function with to_lowercase.
Why does the to_lowercase returning a temporary string change this? I would assume that it's based on the fact that the string would be owned by the closure since it was created within its scope, but why then is the reference to query valid?
3 posts - 3 participants
🏷️ Rust_feed