Crate closure[][src]

A macro for capturing variables on a per variable basis.

With this macro it is possible to specifically designate which variables will be captured by which method. Variables can be either specified to be moved, referenced, mutably referenced or cloned. Unspecified variables will automatically be moved.

The specifiers for each capture type are:

  • move
  • ref
  • ref mut
  • clone

This avoids having to manually declare references ahead of a move closure in order to prevent unwanted moves.

Examples

Spawning a Thread

Instead of having to write:

use std::thread;
use std::sync::{Arc, Barrier, Mutex};

fn main() {
    let mutex = Arc::new(Mutex::new(Vec::new()));
    let barrier = Arc::new(Barrier::new(2));

    let vector_clone = Arc::clone(&mutex);
    let barrier_clone = Arc::clone(&barrier);

    thread::spawn(move || {
        let mut vec = vector_clone.lock().unwrap();
        vec.push(2);
        vec.push(3);
        vec.push(4);

        barrier_clone.wait();
    });

    barrier.wait();
    let mut vec = mutex.lock().unwrap();

    vec.push(1);
    assert_eq!(*vec, &[2, 3, 4, 1]);
}

You can now write:

#[macro_use]
extern crate closure;

use std::thread;
use std::sync::{Arc, Barrier, Mutex};


fn main() {
    let mutex = Arc::new(Mutex::new(Vec::new()));
    let barrier = Arc::new(Barrier::new(2));

    thread::spawn(closure!(clone mutex, clone barrier || {
        let mut vec = mutex.lock().unwrap();
        vec.push(2);
        vec.push(3);
        vec.push(4);

        barrier.wait();
    }));

    barrier.wait();
    let mut vec = mutex.lock().unwrap();

    vec.push(1);
    assert_eq!(*vec, &[2, 3, 4, 1]);
}

Moving cloned smart pointers into thread closures

From the documentation of std::sync::Condvar:

use std::sync::{Arc, Mutex, Condvar};
use std::thread;

fn main() {
    let pair = Arc::new((Mutex::new(false), Condvar::new()));
    let pair2 = pair.clone();

    // Inside of our lock, spawn a new thread, and then wait for it to start.
    thread::spawn(move|| {
        let &(ref lock, ref cvar) = &*pair2;
        let mut started = lock.lock().unwrap();
        *started = true;
        // We notify the condvar that the value has changed.
        cvar.notify_one();
    });

    // Wait for the thread to start up.
    let &(ref lock, ref cvar) = &*pair;
    let mut started = lock.lock().unwrap();
    while !*started {
        started = cvar.wait(started).unwrap();
    }
}

The declaration of pair2 can be avoided:

#[macro_use]
extern crate closure;

use std::sync::{Arc, Mutex, Condvar};
use std::thread;

fn main() {
    let pair = Arc::new((Mutex::new(false), Condvar::new()));

    // Inside of our lock, spawn a new thread, and then wait for it to start.
    thread::spawn(closure!(clone pair || {
        let &(ref lock, ref cvar) = &*pair;
        let mut started = lock.lock().unwrap();
        *started = true;
        // We notify the condvar that the value has changed.
        cvar.notify_one();
    }));

    // Wait for the thread to start up.
    let &(ref lock, ref cvar) = &*pair;
    let mut started = lock.lock().unwrap();
    while !*started {
        started = cvar.wait(started).unwrap();
    }
}

Mixing move and reference captures without having to specifically declare the references

#[macro_use]
extern crate closure;

use closure::*;

fn main() {
    let move_string = String::from("This string should be moved");
    let mut ref_string = String::from("This string will be referenced");

    let closure = closure!(move move_string, ref mut ref_string || {
        ref_string.push_str(&move_string);
        //move_string is dropped at the end of the scope
    });
}

Variable identifiers in the argument position (between the vertical lines) and return type specifications can also be used same as in regular closures.

Limitations

Perhaps counter-intuitively, when designating a move variable, that variable is only moved if it is actually used in the closure code. Also, every closure given to the macro is invariably transformed to a move closure, so closure!(|| {...}) will move capture any variables in the closure block.

Macros

__assert_closure
closure