Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

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.