Is it possible to return a capturing closure from a function?

#1

Suppose I have a library routine, call it foo, that does something useful and requires a sqlite query to do its job. This is another instance of my old problem of preparing a sqlite query once for multiple uses. One Scheme-ish technique I’d like to use in Rust, if possible, is to write a foo_init that prepares the needed query and returns a closure, created in the same scope as the variable holding the prepared statement that captures the statement (the closure probably wants to be of the ‘move’ variety). The caller can then assign the closure to a variable named foo and call foo as needed.

The problem is that closures don’t have identifiable types, so what is the return type of foo_init? I’m guessing the return type wants to be a generic, constrained to have closure characteristics? Is there a trait that describes closureness?

0 Likes

#2

You could use the following:

fn init_foo() -> impl Fn() -> ()

If it captures something or

fn init_foo() -> fn() -> ()

If it doesn’t


To elaborate:
A closure is just a function pointer if it doesn’t capture anything (like variables in the scope, even if they are moved). If it does capture something then you end up with a compiler generated structure to contain the captured variables and also an implementation of the closure. That structure implements the trait Fn (or FnOnce or FnMut depending on the circumstances).

1 Like

#3

To be even more anal, all closures have anonymous types, but the ones with no captures can be coerced into a fn() type. (normally they are zero-sized types)


As far as the Fn traits go, all closures implement FnOnce. Most of them implement FnMut (as long as they don’t consume anything in their captured environment), and only thread-safe ones implement Fn. To give your users the most power, return impl Fn (or barring that, impl FnMut) where possible, and take F: FnOnce (or barring that, FnMut) where possible.

(“where possible” = “where possible without unduely contorting your implementation”)

0 Likes

#4

If we’re picking nits – only sharable closures implement Fn, accessing their captures through &self. Thread-safety is still its own factor of the usual Send/Sync traits.

2 Likes