Expected fn pointer, found fn item

In the following code, everything compiles fine, except the foobarbaz function, and I don't understand what's different with it that makes it not work.

pub fn foo(s: &[u8]) -> std::slice::Split<'_, u8, fn(&u8)->bool> {
    s.split(u8::is_ascii_whitespace)
}

fn filter(_: &[u8]) -> Option<&[u8]> {
    todo!()
}
pub fn bar<'a, I: Iterator<Item=&'a [u8]>>(i: I) -> std::iter::FilterMap<I, fn(&[u8]) -> Option<&[u8]>> {
    i.filter_map(filter)
}

pub struct Foo<'a>(std::iter::FilterMap<std::slice::Split<'a, u8, fn(&u8)->bool>, fn(&[u8]) -> Option<&[u8]>>);

pub fn foobar(s: &[u8]) -> Foo {
    Foo(bar(foo(s)))
}

pub fn foobarbaz(s: &[u8]) -> Foo {
    Foo(s.split(u8::is_ascii_whitespace).filter_map(filter))
}

pub fn qux<'a>(s: std::slice::Split<'a, u8, fn(&u8)->bool>) -> Foo<'a> {
    Foo(s.filter_map(filter))
}

pub fn foobarqux(s: &[u8]) -> Foo {
    qux(s.split(u8::is_ascii_whitespace))
}

Playground

The error is also not super helpful:

error[E0308]: mismatched types
  --> src/lib.rs:19:9
   |
19 |     Foo(s.split(u8::is_ascii_whitespace).filter_map(filter))
   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected fn pointer, found fn item
   |
   = note: expected struct `FilterMap<std::slice::Split<'_, _, for<'r> fn(&'r u8) -> _>, for<'r> fn(&'r [u8]) -> Option<_>>`
              found struct `FilterMap<std::slice::Split<'_, _, for<'r> fn(&'r u8) -> _ {core::num::<impl u8>::is_ascii_whitespace}>, for<'r> fn(&'r [u8]) -> Option<_> {filter}>`

What I don't get is why foobar and foobarqux compile just fine, but not foobarbaz.

In Rust every function (and closure) has a unique type that is impossible to name (the fn item). These unique types can usually be cast or coerced to a simple function pointer.

In many cases the compiler does magic fn item to regular fn pointer conversion for you automatically. In the failing case the automation failed, and it picked a specific complex type for the iterator instead of casting it to a function pointer.

Try u8::is_ascii_whitespace as fn(&u8)->bool

3 Likes

Thank you.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.