]> git.proxmox.com Git - rustc.git/blob - src/doc/rust-by-example/src/fn/closures/capture.md
New upstream version 1.37.0+dfsg1
[rustc.git] / src / doc / rust-by-example / src / fn / closures / capture.md
1 # Capturing
2
3 Closures are inherently flexible and will do what the functionality requires
4 to make the closure work without annotation. This allows capturing to
5 flexibly adapt to the use case, sometimes moving and sometimes borrowing.
6 Closures can capture variables:
7
8 * by reference: `&T`
9 * by mutable reference: `&mut T`
10 * by value: `T`
11
12 They preferentially capture variables by reference and only go lower when
13 required.
14
15 ```rust,editable
16 fn main() {
17 use std::mem;
18
19 let color = "green";
20
21 // A closure to print `color` which immediately borrows (`&`)
22 // `color` and stores the borrow and closure in the `print`
23 // variable. It will remain borrowed until `print` goes out of
24 // scope. `println!` only requires `by reference` so it doesn't
25 // impose anything more restrictive.
26 let print = || println!("`color`: {}", color);
27
28 // Call the closure using the borrow.
29 print();
30 print();
31
32 let mut count = 0;
33
34 // A closure to increment `count` could take either `&mut count`
35 // or `count` but `&mut count` is less restrictive so it takes
36 // that. Immediately borrows `count`.
37 //
38 // A `mut` is required on `inc` because a `&mut` is stored inside.
39 // Thus, calling the closure mutates the closure which requires
40 // a `mut`.
41 let mut inc = || {
42 count += 1;
43 println!("`count`: {}", count);
44 };
45
46 // Call the closure.
47 inc();
48 inc();
49
50 //let _reborrow = &mut count;
51 // ^ TODO: try uncommenting this line.
52
53 // A non-copy type.
54 let movable = Box::new(3);
55
56 // `mem::drop` requires `T` so this must take by value. A copy type
57 // would copy into the closure leaving the original untouched.
58 // A non-copy must move and so `movable` immediately moves into
59 // the closure.
60 let consume = || {
61 println!("`movable`: {:?}", movable);
62 mem::drop(movable);
63 };
64
65 // `consume` consumes the variable so this can only be called once.
66 consume();
67 //consume();
68 // ^ TODO: Try uncommenting this line.
69 }
70 ```
71
72 Using `move` before vertical pipes forces closure
73 to take ownership of captured variables:
74
75 ```rust,editable
76 fn main() {
77 // `Vec` has non-copy semantics.
78 let haystack = vec![1, 2, 3];
79
80 let contains = move |needle| haystack.contains(needle);
81
82 println!("{}", contains(&1));
83 println!("{}", contains(&4));
84
85 // `println!("There're {} elements in vec", haystack.len());`
86 // ^ Uncommenting above line will result in compile-time error
87 // because borrow checker doesn't allow re-using variable after it
88 // has been moved.
89
90 // Removing `move` from closure's signature will cause closure
91 // to borrow _haystack_ variable immutably, hence _haystack_ is still
92 // available and uncommenting above line will not cause an error.
93 }
94 ```
95
96 ### See also:
97
98 [`Box`][box] and [`std::mem::drop`][drop]
99
100 [box]: ../../std/box.md
101 [drop]: https://doc.rust-lang.org/std/mem/fn.drop.html