In Rust, what is `fn() -> ()`?

后端 未结 3 1915
灰色年华
灰色年华 2021-01-19 22:04

I have a grasp of the Fn (capital-F) traits: Fn, FnMut, FnOnce. I understand that they are traits and work like traits.

But wha

相关标签:
3条回答
  • 2021-01-19 22:38

    It is a function pointer type.

    It refers only to a function, not a closure, since it contains just the address of the function not the captured environment a closure needs.

    A Fn trait (capital F) can refer either to a closure or a function.

    0 讨论(0)
  • 2021-01-19 22:45

    fn is the type for a function pointer. See also here in the documentation: https://doc.rust-lang.org/std/primitive.fn.html

    0 讨论(0)
  • 2021-01-19 22:53

    prog-fh's answer is essentially correct, but lacks some nuance. Rust has three kinds of function-like types:

    1. Function items are what you get when you create a function by using fn foo() {...}. It's also the type of the constructor of a tuple-like struct or enum variant. Function items are zero-sized (they contain no data), and every non-generic function has a unique, unnameable function item type. In error messages, the compiler displays these "Voldemort types" as something like fn() -> () {foo} (with the name of the function in {}).

    2. Closures are values similar to function items, but closures may contain data: copies of or references to whatever variables they capture from their environment. As you already know, you create a closure by using closure syntax (|args| expression). Like function items, closures have unique, unnameable types (rendered by the compiler something like [closure@src/main.rs:4:11: 4:23]).

    3. Function pointers are what you're asking about: the types that look like fn() -> (). Function pointers cannot contain data, but they are not zero-sized; as their name suggests, they are pointers. A function pointer may point either to a function item, or to a closure that captures nothing, but it cannot be null.

    Function items and closures are automatically coerced to the relevant function pointer type when possible, so that's why let f: fn(i32) = |_| (); works: because the closure captures nothing, it can be coerced to a function pointer.

    All three function-like types implement the relevant Fn, FnMut and FnOnce traits (except that closures might not implement Fn or FnMut depending on what they capture). Function items and function pointers also implement Copy, Clone, Send and Sync (closures only implement these traits when all their contents do).

    Performance-wise, function pointers are something of a compromise between generics and trait objects. They have to be dereferenced to be called, so calling a function pointer may be slower than calling a function item or closure directly, but still faster than calling a dyn Fn trait object, which involves a vtable lookup in addition to the indirect call.

    References

    • What's the practical difference between fn item and fn pointer?
    • Why design a language with unique anonymous types?
    • How do I make a struct for FFI that contains a nullable function pointer?
    • Why does passing a closure to function which accepts a function pointer not work?
    0 讨论(0)
提交回复
热议问题