I'm doing advent of code and ran into an error with closures borrowing things for longer than (I think) is necessary.
Here's a more simplified example of the error I'm running into.
This code can be interpreted as "I want all of the elements in this iterator that are not in this set; Take them and insert them into the set.
use std::collections::HashSet;
fn main() {
let mut my_set: HashSet<i32> = HashSet::default();
my_set.insert(2);
my_set.insert(3);
[1, 2, 3, 4]
.into_iter()
.filter(|num| !my_set.contains(num))
.for_each(|num| {
my_set.insert(num);
});
}
The error I get back from the compiler says that the filter
closure is borrowing my_set
immutably AND the closure passed to for_each
is borrowing my_set
mutably. This makes perfect sense: you cannot have a mutable reference AND an immutable reference at the same time.
But (I'm pretty sure) these references don't exist at the same time! I mean, the fact that we are iterating over some element in the for_each
closure implies that we have ran (and returned from and passed) the filter
closure.
maybe the answer? why is this unsafe tho??
Some thinking, reading, and gpt'ing has lead me to think this is because the iterator basically runs filter->for_each element-wise; In other words, we don't filter everything, then for_each everything. So the filter closure is still around while the for_each closure is running.
Is that the right way of thinking about this error? In my head, a closure borrowing something isn't really an issue if that closure isn't currently running.
my question is more: why does this make the compiler angry?
than it is: how can I write code that makes the compiler happy (just use a for loop instead of two different closures, or use for_each
with an if statement instead of a filter)
Thanks so much for your time! Happy holidays!