As far as I understand it, closures are implemented as anonymous structs that wrap captured variables and then implement one of the Fn
traits based on inference.
For example, this:
fn main() {
let my_val = 1i32;
let print = || println!("{}", my_val);
print();
}
is equivalent to:
struct AnonymousClosure1<'a> {
my_val: &'a i32,
}
impl<'a> FnOnce for AnonymousClosure1<'a> {
type Output = ();
extern "rust-call" fn call_once(self) -> {
println!("{}", self.my_val);
}
}
fn main() {
let my_val = 1i32;
let closure = AnonymousClosure1{
my_val: &my_val,
};
closure();
}
For a closure that doesn’t capture any values, I assume this is still done, but with a unit-struct where:
fn main() {
let closure = || println!("Hello, world!");
closure();
}
is roughly equivalent to:
struct AnonymousClosure1;
impl FnOnce for AnonymousClosure1 {
type Output = ();
extern "rust-call" fn call_once(self) {
println!("Hello, world!");
}
}
fn main() {
let closure = AnonymousClosure1;
closure();
}
This seems like a lot of extra generated code for what is essentially an anonymous function. These could, instead, be implemented as bare anonymous functions and coerced to function pointers, which would expand their versatility:
fn anonymous_fn() {
println!("Hello, world!");
}
fn main() {
let closure = anonymous_fn;
anonymous_fn();
takes_fn_ptr(anonymous_fn);
}
fn takes_fn_ptr(fn_ptr: fn()) {
fn_ptr();
}
I don’t know if function pointers are very prevalent anymore, since they coerce to closures which most APIs prefer to accept, but there might be some places where they’re still useful. I think FFI might be one of them. If closures could work with FFI, that could be a pretty large ergonomics win for any Rust code integrating with C code that makes heavy use of function pointers. Obviously, capturing closures wouldn’t work, but non-capturing closures (anonymous functions) could.