(Potential) Rust Closure Types

Fn FnMut FnOnce &T &Fn< Args… , Ret >

Stack closure with immutable environment. Can be copied. Can't borrow & as &mut . Can't borrow & as &move . &mut T &mut Fn< Args… , Ret >

No benefit over &Fn< Args… , Ret > . &mut FnMut< Args… , Ret >

Stack closure which may mutate its environment. Can't be copied.

Equivalent to current | Args… | -> Ret . Can't borrow &mut as &move . &move T &move Fn< Args… , Ret >

No benefit over &Fn< Args… , Ret > . &move FnMut< Args… , Ret >

No benefit over &mut FnMut< Args… , Ret > . &move FnOnce< Args… , Ret >

Stack closure which may move from its environment. Can't be copied. Can only be called once. (unboxed) T < T : Fn< Args… , Ret >>

Unboxed closure with immutable environment. < T : FnMut< Args… , Ret >>

Unboxed closure which may mutate its environment.

< T : FnOnce< Args… , Ret >>

Unboxed closure which may move from its environment. Can only be called once.

~T ~Fn< Args… , Ret >

Owned heap closure with immutable environment. ~FnMut< Args… , Ret >

Owned heap closure which may mutate its environment.

Equivalent to old ~fn( Args… ) -> Ret and to std::function< Ret ( Args… )> in C++. ~FnOnce< Args… , Ret >

Owned heap closure which may move from its environment. Can only be called once.

Equivalent to current proc( Args… ) -> Ret . Rc<T> Rc<Fn< Args… , Ret >>

Reference counted shared heap closure with immutable environment. Can't borrow Rc as &mut . Can't borrow Rc as &move . Gc<T> Gc<Fn< Args… , Ret >>

Garbage collected shared heap closure with immutable environment.

Equivalent (I believe) to the old @fn( Args… ) -> Ret and to closures in many functional languages. Can't borrow Gc as &mut . Can't borrow Gc as &move . Rc<RefCell<T>> Rc<RefCell<Fn< Args… , Ret >>>

No benefit over Rc<Fn< Args… , Ret >> . Rc<RefCell<FnMut< Args… , Ret >>>

Reference counted shared heap closure which may mutate its environment. Can't borrow RefCell as &move .

(But &move doesn't even exist. This might be possible.) Gc<RefCell<T>> Gc<RefCell<Fn< Args… , Ret >>>

No benefit over Gc<Fn< Args… , Ret >> . Gc<RefCell<FnMut< Args… , Ret >>>

Garbage collected shared heap closure which may mutate its environment.

(Was there an @mut fn( Args… ) -> Ret ? If so, equivalent to that.) Can't borrow RefCell as &move .

(But &move doesn't even exist. This might be possible.) Exists Doesn't exist, but useful! Strictly inferior to another type Useless (can't be called) Show < Args… , Ret >

Explanation

This is a table of existing and possible closure types in Rust. It is intended for an audience already highly familiar with Rust.

Its purpose is to illustrate the universe of potential closure types which can be derived from a combination of a (built-in or library defined) reference type and a closure trait, the subset of those which have uniquely useful characteristics (in white), and the subset of those which currently exist in the language (in green; as you can see, it is small).

The three traits corresponding to the three columns are:

trait Fn<Args…, Ret> {

fn call(&self, Args…) -> Ret;

}



trait FnMut<Args…, Ret> {

fn call_mut(&mut self, Args…) -> Ret;

}



trait FnOnce<Args…, Ret> {

fn call_once(&move self, Args…) -> Ret;

}

&move does not currently exist. The possibility was discussed in issue #10672 (where @nikomatsakis refers to it as &my ; I prefer the name &move ). It can be approximated for owned heap closures (but not anything else, so basically only proc ) as ~self . I am also assuming the existence of some form of "dynamically-sized types" and some way to abstract over the number of parameters a function has.

The traits are progressively more restrictive on the caller as you move downwards and progressively more restrictive on the callee (the closure itself) as you move upwards. With an Fn , the caller may share it and call it freely but the closure may only read from its environment. With an FnOnce , the caller must have sole ownership of the closure and can only call it once(!), while the closure itself is free to mutate or move from its environment as it pleases. ( FnMut , of course, is in between.)

These in fact form a subtype relationship of sorts: an impl of any of these traits can be derived from an impl of any of the traits above it. (Given impl Fn , call_mut can forward to call by simply freezing the &mut self reference to an immutable & , and analogously for the others.) This could be formalized using supertraits (i.e. trait Fn: FnMut , trait FnMut: FnOnce ), but this would be annoying when implementing Fn manually for some type.

As is visible from the chart, unboxed closures have basically the same characteristics as owned heap closures, and the same is true between reference counted and garbage collected shared heap closures.

My thanks to Kang Seonghoon for allowing me to borrow the code from his awesome Periodic Table of Rust Types, which I have butchered into a state of vague acceptability for this purpose.

Content copyright © 2014 Gábor Lehel. Code copyright © 2014 Kang Seonghoon & Gábor Lehel. This work is licensed under a Creative Commons Attribution 4.0 International License.