Macro taken::take
[−]
[src]
macro_rules! take { [$var:ident, $($rest:tt)*] => { ... }; [$var:ident as $v:ident, $($rest:tt)*] => { ... }; [mut $var:ident, $($rest:tt)*] => { ... }; [mut $var:ident as $v:ident, $($rest:tt)*] => { ... }; [&$var:ident, $($rest:tt)*] => { ... }; [&$var:ident as $v:ident, $($rest:tt)*] => { ... }; [&mut $var:ident, $($rest:tt)*] => { ... }; [&mut $var:ident as $v:ident, $($rest:tt)*] => { ... }; [=$var:ident, $($rest:tt)*] => { ... }; [=$var:ident as $v:ident, $($rest:tt)*] => { ... }; [=mut $var:ident, $($rest:tt)*] => { ... }; [=mut $var:ident as $v:ident, $($rest:tt)*] => { ... }; [$var:ident] => { ... }; [$var:ident as $v:ident] => { ... }; [mut $var:ident] => { ... }; [mut $var:ident as $v:ident] => { ... }; [&$var:ident] => { ... }; [&$var:ident as $v:ident] => { ... }; [&mut $var:ident] => { ... }; [&mut $var:ident as $v:ident] => { ... }; [=$var:ident] => { ... }; [=$var:ident as $v:ident] => { ... }; [=mut $var:ident] => { ... }; [=mut $var:ident as $v:ident] => { ... }; [] => { ... }; }
Take ownership of specific variables.
One of the main use cases is closures. Closures try to be "smart" about how
much scope they capture. If you don't mutate a variable they take &var
,
if you do mutate they take &mut var
. However, if you require ownership
you use move
, i.e. move || {... do stuff with var...}
... right?
The problem with move
is that it moves every variable that is referenced. If you only need
to move a few variables it can be a pain. Interestingly, you can tell the compiler to only move
specific variables like so:
let x = x; let y = y; // ... etc
But this is quite silly and not obvious to someone who doesn't know about it. Instead, use the
take!
macro and your code will be self documenting.
You can also use take!
to perform a clone or assert to the compiler that you are only taking
a certain kind of reference. See the examples for more.
Downsides
If you use this macro (or let x = x
) then the closure becomes FnOnce
.
Unfortunately the best explanation of the trade offs is currently a reddit thread. Please help flush out these docs more!
Examples
Changing Ownership
It is easy to change the mutability and take references or clones.
let (a, mut b, c, d, e, f) = (1, 2, 3, 4, 5, 6); take!( &a, // let a = &a; &mut b, // let b = &mut b; c, // let c = c; mut d, // let mut d = d; =e, // let e = e.clone(); =mut f, // let mut e = e.clone(); );
Changing Ownership and Renaming
You can also rename one or more of the variables using as
:
let (var_a, mut var_b, var_c, var_d, var_e, var_f) = (1, 2, 3, 4, 5, 6); take!( &var_a as a, // let a = &var_a; &mut var_b as b, // let b = &mut var_b; var_c as c, // let c = var_c; mut var_d as d, // let mut d = var_d; =var_e as e, // let e = var_e.clone(); =mut var_f as f, // let mut e = var_e.clone(); );
Usecase: Closures
Closures are one of the main use cases.
#[macro_use] extern crate taken; // make them all mutable to demo that we can control // mutability using `take!` let mut w = vec![1, 2, 3]; let mut x = vec![1, 2, 3]; let mut y = vec![1, 2, 3]; let mut z = vec![10]; { let closure = || { take!(&w, &mut x, y, mut z); // w.push(5); // ERROR: cannot borrow as mutable x.push(4); // mutate reference to x z.push(10); // we own `mut z` println!("&x: {:?}", &x); println!("moved y: {:?}", y); println!("moved mut z: {:?}", z); // y and z are dropped }; closure(); } println!("&w after: {:?}", w); // We can still print w! println!("&x after: {:?}", x); // We can still print x! // println!("y after: {:?}", y); // ERROR: use of moved value // println!("z after: {:?}", z); // ERROR: use of moved value
Usecase: Threads
Threads are another primary use case, as threads use closures. Threads in particular are always
FnOnce
and often find themselves cloning and moving specific variables.
use std::thread::spawn; use std::sync::mpsc::channel; #[macro_use] extern crate taken; let (send, recv) = channel(); { let th = spawn(|| { take!(send); // let send = send; send.send("foo").unwrap(); }); th.join().unwrap(); } println!("received: {:?}", recv.into_iter().collect::<Vec<_>>());