Goal: Understand the following block of code.
fn find_entities<F>(entities: &Vec<Entity>, f: F) -> Vec<Entity>
where for<'r> F: (Fn(&'r &Entity) -> bool)
{
entities.iter()
.filter(f)
.map(|x| (*x).clone())
.collect::<Vec<_>>()
}
It began as this:
fn find_entities(entities: &Vec<Entity>) -> Vec<Entity>
{
entities.iter()
.filter(|e| e.kind == EntityType::Foo)
.map(|x| *x)
.collect::<Vec<_>>()
}
Then I tried to add a function parameter.
fn find_entities<F>(entities: &Vec<Entity>, f: F) -> Vec<Entity>
where F: Fn(&Entity) -> bool
{
entities.iter()
.filter(f)
.map(|x| *x)
.collect::<Vec<_>>()
}
However the compiler complained. (Please note: I'm writing all this up after the fact and salvaging the right compiler errors was difficult. They may not be exact so consider things more of a guide than exactly what I was seeing.)
error[E0277]: the trait bound `for<'r> F: std::ops::FnMut<(&'r &Entity,)>` is not satisfied
--> src/main.rs:24:14
|
24 | .filter(f)
| ^^^^^^ the trait `for<'r> std::ops::FnMut<(&'r &Entity,)>` is not implemented for `F`
|
= help: consider adding a `where for<'r> F: std::ops::FnMut<(&'r &Entity,)>` bound
After struggling a bit to make sense of this error message a google search turned up the following on StackOverflow: Stack Overflow post
Though the compiler suggest the following, I was not able to make it work.
where for<'r> F: std::ops::Fn<(&'r &Entity,)>
It took several tries to arrive at the solution.
where for<'r> F: (Fn(&'r &Entity) -> bool)
After even more googling to figure out what all this means I stumbled upon Rust nomicon section on trait bounds, which is the first time I’ve even seen the where for syntax used outside of the compiler.
So clearly I’ve stumbled onto something above my current pay grade. What I think is happening is that because my parameter f is being passed to filter, which operates on an iterator lifetimes are involved. So the trait bound needs to specify a lifetime.
At this point I’m wondering if I’ve done something really obtuse or backward to require so much. I assume if I simply use iterator in place and just pass in the closure then things would be significantly more simple.
Any clarity or information on this at all would be appreciated. It is not an easy thing to google for and find more information.