简体   繁体   中英

How to create a rust filter predicate for an iterator?

pub struct S{
    a: u32
}
fn main() {
    let ve = vec![S{a: 1}, S{a: 2}];
    ve.iter().filter(filter_function);
}

fn filter_function(s: &S) -> bool {
    todo!()
}

Gives

error[E0631]: type mismatch in function arguments
   --> src/main.rs:6:22
    |
6   |     ve.iter().filter(filter_function);
    |               ------ ^^^^^^^^^^^^^^^ expected signature of `for<'r> fn(&'r &S) -> _`
    |               |
    |               required by a bound introduced by this call
...
9   | fn filter_function(s: &S) -> bool {
    | --------------------------------- found signature of `for<'r> fn(&'r S) -> _`
    |
note: required by a bound in `filter`

https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=caf542348c2b744abace8e7b6b30d766

And I have no idea why. The signatures are the same. What is wrong?

The signatures aren't quite the same. The expected type is a function which takes a &'r &S , while your function takes a &'r S . One has an extra layer of indirection.

You need a function that takes a double reference and calls filter_function with a single reference. We can do that with an explicit dereference.

ve.iter().filter(|x| filter_function(*x));

However, generally, Rust is pretty good at sorting out these kinds of dereferencing problems in lambdas, so we can simply write

ve.iter().filter(|x| filter_function(x));

and Rust is smart enough to handle the double reference for us.

It's worth mentioning that there should be no performance hit for the extra lambda. filter takes a generic argument, which means it'll be statically dispatched and hence will be very easy for an optimizer to inline. So the performance should be equivalent to having a top-level function.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM