What exactly is `fn` when used as a type (not when declaring a function)? Is it only for FFI?

Consider this code:

fn foo(f: &fn(i32)) {
}

fn bar(a: i32) {
}

fn main() {
    foo(&bar);
}

The error is:

error[E0308]: mismatched types
 --> <anon>:8:9
  |
8 |     foo(&bar);
  |         ^^^^ expected fn pointer, found fn item
  |
  = note: expected type `&fn(i32)`
  = note:    found type `&fn(i32) {bar}`

What exactly is fn when used as a type? I've used extern fn and unsafe extern fn when doing C FFI where I need to pass in function pointers, but I guess I don't really understand what these types are. Are they solely used for FFI? Do they implement the Fn trait? Is there a real use for fn as a type without extern?

I'm not sure what the compiler is saying exactly here, but a function pointer in your example is just "fn(i32)", not "&fn(i32)"; likewise, you'd call it "foo(bar)", not "foo(&bar)".

fn, as mentioned, is a plain function pointer (or value) - it's not a closure and therefore cannot capture the environment. An fn can be passed wherever an Fn is expected, but not the other way.

1 Like

That makes sense, thanks. I am curious about that error message if anyone knows what it's talking about.

I'd like to see the docs specifically call out using fn in the Function Pointers section of the docs.

There's also the recently-merged RFC: Allow coercing non-capturing closures to function pointers.

1 Like

Looks like it's related to this: The Rust Reference has moved. Basically, it looks like if you do &bar you're getting a reference to a concrete fn item/type, unique to bar itself, and this kills the coercion to a "generic" fn type that we would otherwise want.

1 Like