]>
Commit | Line | Data |
---|---|---|
13cf67c4 XL |
1 | # Closure types |
2 | ||
3 | A [closure expression] produces a closure value with a unique, anonymous type | |
4 | that cannot be written out. A closure type is approximately equivalent to a | |
5 | struct which contains the captured variables. For instance, the following | |
6 | closure: | |
7 | ||
8 | ```rust | |
9 | fn f<F : FnOnce() -> String> (g: F) { | |
10 | println!("{}", g()); | |
11 | } | |
12 | ||
13 | let mut s = String::from("foo"); | |
14 | let t = String::from("bar"); | |
15 | ||
16 | f(|| { | |
3dfed10e | 17 | s += &t; |
13cf67c4 XL |
18 | s |
19 | }); | |
20 | // Prints "foobar". | |
21 | ``` | |
22 | ||
23 | generates a closure type roughly like the following: | |
24 | ||
60c5eb7d | 25 | <!-- ignore: simplified, requires unboxed_closures, fn_traits --> |
13cf67c4 XL |
26 | ```rust,ignore |
27 | struct Closure<'a> { | |
28 | s : String, | |
29 | t : &'a String, | |
30 | } | |
31 | ||
60c5eb7d XL |
32 | impl<'a> FnOnce<()> for Closure<'a> { |
33 | type Output = String; | |
13cf67c4 XL |
34 | fn call_once(self) -> String { |
35 | self.s += &*self.t; | |
36 | self.s | |
37 | } | |
38 | } | |
39 | ``` | |
40 | ||
41 | so that the call to `f` works as if it were: | |
42 | ||
60c5eb7d | 43 | <!-- ignore: continuation of above --> |
13cf67c4 XL |
44 | ```rust,ignore |
45 | f(Closure{s: s, t: &t}); | |
46 | ``` | |
47 | ||
48 | ## Capture modes | |
49 | ||
50 | The compiler prefers to capture a closed-over variable by immutable borrow, | |
51 | followed by unique immutable borrow (see below), by mutable borrow, and finally | |
136023e0 XL |
52 | by move. It will pick the first choice of these that is compatible with how the |
53 | captured variable is used inside the closure body. The compiler does not take | |
54 | surrounding code into account, such as the lifetimes of involved variables, or | |
55 | of the closure itself. | |
13cf67c4 XL |
56 | |
57 | If the `move` keyword is used, then all captures are by move or, for `Copy` | |
58 | types, by copy, regardless of whether a borrow would work. The `move` keyword is | |
59 | usually used to allow the closure to outlive the captured values, such as if the | |
60 | closure is being returned or used to spawn a new thread. | |
61 | ||
62 | Composite types such as structs, tuples, and enums are always captured entirely, | |
63 | not by individual fields. It may be necessary to borrow into a local variable in | |
64 | order to capture a single field: | |
65 | ||
66 | ```rust | |
67 | # use std::collections::HashSet; | |
68 | # | |
69 | struct SetVec { | |
70 | set: HashSet<u32>, | |
71 | vec: Vec<u32> | |
72 | } | |
73 | ||
74 | impl SetVec { | |
75 | fn populate(&mut self) { | |
76 | let vec = &mut self.vec; | |
77 | self.set.iter().for_each(|&n| { | |
78 | vec.push(n); | |
79 | }) | |
80 | } | |
81 | } | |
82 | ``` | |
83 | ||
84 | If, instead, the closure were to use `self.vec` directly, then it would attempt | |
85 | to capture `self` by mutable reference. But since `self.set` is already | |
86 | borrowed to iterate over, the code would not compile. | |
87 | ||
88 | ## Unique immutable borrows in captures | |
89 | ||
90 | Captures can occur by a special kind of borrow called a _unique immutable | |
91 | borrow_, which cannot be used anywhere else in the language and cannot be | |
92 | written out explicitly. It occurs when modifying the referent of a mutable | |
93 | reference, as in the following example: | |
94 | ||
95 | ```rust | |
96 | let mut b = false; | |
97 | let x = &mut b; | |
98 | { | |
99 | let mut c = || { *x = true; }; | |
100 | // The following line is an error: | |
101 | // let y = &x; | |
102 | c(); | |
103 | } | |
104 | let z = &x; | |
105 | ``` | |
106 | ||
107 | In this case, borrowing `x` mutably is not possible, because `x` is not `mut`. | |
108 | But at the same time, borrowing `x` immutably would make the assignment illegal, | |
109 | because a `& &mut` reference may not be unique, so it cannot safely be used to | |
110 | modify a value. So a unique immutable borrow is used: it borrows `x` immutably, | |
111 | but like a mutable borrow, it must be unique. In the above example, uncommenting | |
112 | the declaration of `y` will produce an error because it would violate the | |
113 | uniqueness of the closure's borrow of `x`; the declaration of z is valid because | |
114 | the closure's lifetime has expired at the end of the block, releasing the borrow. | |
115 | ||
116 | ## Call traits and coercions | |
117 | ||
118 | Closure types all implement [`FnOnce`], indicating that they can be called once | |
119 | by consuming ownership of the closure. Additionally, some closures implement | |
120 | more specific call traits: | |
121 | ||
122 | * A closure which does not move out of any captured variables implements | |
123 | [`FnMut`], indicating that it can be called by mutable reference. | |
124 | ||
125 | * A closure which does not mutate or move out of any captured variables | |
126 | implements [`Fn`], indicating that it can be called by shared reference. | |
127 | ||
128 | > Note: `move` closures may still implement [`Fn`] or [`FnMut`], even though | |
129 | > they capture variables by move. This is because the traits implemented by a | |
130 | > closure type are determined by what the closure does with captured values, | |
131 | > not how it captures them. | |
132 | ||
133 | *Non-capturing closures* are closures that don't capture anything from their | |
3dfed10e XL |
134 | environment. They can be coerced to function pointers (e.g., `fn()`) |
135 | with the matching signature. | |
13cf67c4 XL |
136 | |
137 | ```rust | |
138 | let add = |x, y| x + y; | |
139 | ||
140 | let mut x = add(5,7); | |
141 | ||
142 | type Binop = fn(i32, i32) -> i32; | |
143 | let bo: Binop = add; | |
144 | x = bo(5,7); | |
145 | ``` | |
146 | ||
147 | ## Other traits | |
148 | ||
149 | All closure types implement [`Sized`]. Additionally, closure types implement the | |
150 | following traits if allowed to do so by the types of the captures it stores: | |
151 | ||
152 | * [`Clone`] | |
153 | * [`Copy`] | |
154 | * [`Sync`] | |
155 | * [`Send`] | |
156 | ||
157 | The rules for [`Send`] and [`Sync`] match those for normal struct types, while | |
158 | [`Clone`] and [`Copy`] behave as if [derived]. For [`Clone`], the order of | |
159 | cloning of the captured variables is left unspecified. | |
160 | ||
161 | Because captures are often by reference, the following general rules arise: | |
162 | ||
163 | * A closure is [`Sync`] if all captured variables are [`Sync`]. | |
164 | * A closure is [`Send`] if all variables captured by non-unique immutable | |
165 | reference are [`Sync`], and all values captured by unique immutable or mutable | |
166 | reference, copy, or move are [`Send`]. | |
167 | * A closure is [`Clone`] or [`Copy`] if it does not capture any values by | |
168 | unique immutable or mutable reference, and if all values it captures by copy | |
169 | or move are [`Clone`] or [`Copy`], respectively. | |
170 | ||
416331ca XL |
171 | [`Clone`]: ../special-types-and-traits.md#clone |
172 | [`Copy`]: ../special-types-and-traits.md#copy | |
173 | [`FnMut`]: ../../std/ops/trait.FnMut.html | |
174 | [`FnOnce`]: ../../std/ops/trait.FnOnce.html | |
175 | [`Fn`]: ../../std/ops/trait.Fn.html | |
176 | [`Send`]: ../special-types-and-traits.md#send | |
177 | [`Sized`]: ../special-types-and-traits.md#sized | |
178 | [`Sync`]: ../special-types-and-traits.md#sync | |
179 | [closure expression]: ../expressions/closure-expr.md | |
180 | [derived]: ../attributes/derive.md |