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

Table of Contents

Issue

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

But what about fn (lowercase-f)? It gets a different coloring in editors, which tells me it’s not a trait. It can also be used in some places where the others can’t (and vice-versa), though it seems to behave similarly in other cases. I couldn’t find anything explaining it directly in the docs.

Solution

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 [[email protected]/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. However, in real code there are many variables that confound naive analysis; if the difference in performance is important to you, you should measure it instead of guessing which is faster.

References

Answered By – trent

Answer Checked By – Mildred Charles (BugsFixing Admin)

Leave a Reply

Your email address will not be published.