Closure Desugaring
Once captures are explicit, desugaring closures into ADTs becomes straightforward.
A closure becomes a struct, with one field per move($expr) expression, and that field is
initialized with $expr. That struct then implements the appropriate Fn* traits. In the new
function body, what was a move(..) expression is replaced with the appropriate field expression.
Let’s take our previous examples again:
#![allow(unused)]
fn main() {
let mut increment = || {
let place x = *move(&mut x);
x = copy!(x) + 1
};
// desugars to
struct Closure<'a> {
capture1: &'a mut u32,
}
impl FnOnce<()> for Closure<'_> {
type Output = ();
fn call_once(mut self, args: ()) {
self.call_mut(args)
}
}
impl FnMut<()> for Closure<'_> {
fn call_mut(&mut self, _args: ()) {
let place x = *self.capture1;
x = copy!(x) + 1
}
}
let mut increment = Closure { capture1: &mut x };
}
and
#![allow(unused)]
fn main() {
let mut replace = |new: u32| {
let place x = move(x);
Option::replace(&mut x, copy!(new))
};
// desugars to
struct Closure {
capture1: u32,
}
impl FnOnce<(u32,)> for Closure {
type Output = Option<u32>;
fn call_once(mut self, args: (u32,)) -> Option<u32> {
self.call_mut(args)
}
}
impl FnMut<(u32,)> for Closure {
fn call_mut(&mut self, (new,): (u32,)) -> Option<u32> {
let place x = self.capture1;
Option::replace(&mut x, copy!(new))
}
}
let mut replace = Closure { capture1: x };
}
To clean up the newly generated closure expressions, we run the Intermediate Subexpression Elimination, Explicit Copies/Moves and Desugaring Bindings steps again.
After this step, there are no closure expressions left.