]>
Commit | Line | Data |
---|---|---|
1a4d82fc JJ |
1 | % Closures |
2 | ||
b039eaaf SL |
3 | Sometimes it is useful to wrap up a function and _free variables_ for better |
4 | clarity and reuse. The free variables that can be used come from the | |
5 | enclosing scope and are ‘closed over’ when used in the function. From this, we | |
6 | get the name ‘closures’ and Rust provides a really great implementation of | |
7 | them, as we’ll see. | |
1a4d82fc | 8 | |
c34b1796 | 9 | # Syntax |
1a4d82fc | 10 | |
c34b1796 | 11 | Closures look like this: |
1a4d82fc | 12 | |
c34b1796 AL |
13 | ```rust |
14 | let plus_one = |x: i32| x + 1; | |
15 | ||
16 | assert_eq!(2, plus_one(1)); | |
17 | ``` | |
18 | ||
bd371182 | 19 | We create a binding, `plus_one`, and assign it to a closure. The closure’s |
c34b1796 AL |
20 | arguments go between the pipes (`|`), and the body is an expression, in this |
21 | case, `x + 1`. Remember that `{ }` is an expression, so we can have multi-line | |
22 | closures too: | |
23 | ||
24 | ```rust | |
25 | let plus_two = |x| { | |
26 | let mut result: i32 = x; | |
27 | ||
28 | result += 1; | |
29 | result += 1; | |
30 | ||
31 | result | |
32 | }; | |
33 | ||
34 | assert_eq!(4, plus_two(2)); | |
35 | ``` | |
36 | ||
62682a34 | 37 | You’ll notice a few things about closures that are a bit different from regular |
b039eaaf | 38 | named functions defined with `fn`. The first is that we did not need to |
c34b1796 AL |
39 | annotate the types of arguments the closure takes or the values it returns. We |
40 | can: | |
41 | ||
42 | ```rust | |
43 | let plus_one = |x: i32| -> i32 { x + 1 }; | |
44 | ||
45 | assert_eq!(2, plus_one(1)); | |
46 | ``` | |
47 | ||
b039eaaf SL |
48 | But we don’t have to. Why is this? Basically, it was chosen for ergonomic |
49 | reasons. While specifying the full type for named functions is helpful with | |
50 | things like documentation and type inference, the full type signatures of | |
51 | closures are rarely documented since they’re anonymous, and they don’t cause | |
52 | the kinds of error-at-a-distance problems that inferring named function types | |
53 | can. | |
c34b1796 | 54 | |
b039eaaf SL |
55 | The second is that the syntax is similar, but a bit different. I’ve added |
56 | spaces here for easier comparison: | |
c34b1796 AL |
57 | |
58 | ```rust | |
62682a34 SL |
59 | fn plus_one_v1 (x: i32) -> i32 { x + 1 } |
60 | let plus_one_v2 = |x: i32| -> i32 { x + 1 }; | |
61 | let plus_one_v3 = |x: i32| x + 1 ; | |
1a4d82fc JJ |
62 | ``` |
63 | ||
62682a34 | 64 | Small differences, but they’re similar. |
1a4d82fc | 65 | |
c34b1796 | 66 | # Closures and their environment |
1a4d82fc | 67 | |
b039eaaf SL |
68 | The environment for a closure can include bindings from its enclosing scope in |
69 | addition to parameters and local bindings. It looks like this: | |
c34b1796 AL |
70 | |
71 | ```rust | |
72 | let num = 5; | |
73 | let plus_num = |x: i32| x + num; | |
74 | ||
75 | assert_eq!(10, plus_num(5)); | |
1a4d82fc JJ |
76 | ``` |
77 | ||
c34b1796 AL |
78 | This closure, `plus_num`, refers to a `let` binding in its scope: `num`. More |
79 | specifically, it borrows the binding. If we do something that would conflict | |
80 | with that binding, we get an error. Like this one: | |
81 | ||
82 | ```rust,ignore | |
83 | let mut num = 5; | |
84 | let plus_num = |x: i32| x + num; | |
1a4d82fc | 85 | |
c34b1796 AL |
86 | let y = &mut num; |
87 | ``` | |
1a4d82fc | 88 | |
c34b1796 AL |
89 | Which errors with: |
90 | ||
91 | ```text | |
92 | error: cannot borrow `num` as mutable because it is also borrowed as immutable | |
93 | let y = &mut num; | |
94 | ^~~ | |
95 | note: previous borrow of `num` occurs here due to use in closure; the immutable | |
96 | borrow prevents subsequent moves or mutable borrows of `num` until the borrow | |
97 | ends | |
98 | let plus_num = |x| x + num; | |
99 | ^~~~~~~~~~~ | |
100 | note: previous borrow ends here | |
1a4d82fc | 101 | fn main() { |
c34b1796 AL |
102 | let mut num = 5; |
103 | let plus_num = |x| x + num; | |
62682a34 | 104 | |
c34b1796 AL |
105 | let y = &mut num; |
106 | } | |
107 | ^ | |
108 | ``` | |
109 | ||
bd371182 | 110 | A verbose yet helpful error message! As it says, we can’t take a mutable borrow |
c34b1796 AL |
111 | on `num` because the closure is already borrowing it. If we let the closure go |
112 | out of scope, we can: | |
113 | ||
114 | ```rust | |
115 | let mut num = 5; | |
116 | { | |
117 | let plus_num = |x: i32| x + num; | |
118 | ||
119 | } // plus_num goes out of scope, borrow of num ends | |
1a4d82fc | 120 | |
c34b1796 AL |
121 | let y = &mut num; |
122 | ``` | |
123 | ||
124 | If your closure requires it, however, Rust will take ownership and move | |
62682a34 | 125 | the environment instead. This doesn’t work: |
c34b1796 AL |
126 | |
127 | ```rust,ignore | |
128 | let nums = vec![1, 2, 3]; | |
129 | ||
130 | let takes_nums = || nums; | |
131 | ||
132 | println!("{:?}", nums); | |
133 | ``` | |
134 | ||
62682a34 | 135 | We get this error: |
c34b1796 AL |
136 | |
137 | ```text | |
138 | note: `nums` moved into closure environment here because it has type | |
139 | `[closure(()) -> collections::vec::Vec<i32>]`, which is non-copyable | |
140 | let takes_nums = || nums; | |
62682a34 | 141 | ^~~~~~~ |
c34b1796 AL |
142 | ``` |
143 | ||
144 | `Vec<T>` has ownership over its contents, and therefore, when we refer to it | |
bd371182 | 145 | in our closure, we have to take ownership of `nums`. It’s the same as if we’d |
c34b1796 AL |
146 | passed `nums` to a function that took ownership of it. |
147 | ||
148 | ## `move` closures | |
149 | ||
150 | We can force our closure to take ownership of its environment with the `move` | |
151 | keyword: | |
1a4d82fc | 152 | |
c34b1796 AL |
153 | ```rust |
154 | let num = 5; | |
155 | ||
156 | let owns_num = move |x: i32| x + num; | |
157 | ``` | |
158 | ||
159 | Now, even though the keyword is `move`, the variables follow normal move semantics. | |
160 | In this case, `5` implements `Copy`, and so `owns_num` takes ownership of a copy | |
bd371182 | 161 | of `num`. So what’s the difference? |
c34b1796 AL |
162 | |
163 | ```rust | |
164 | let mut num = 5; | |
165 | ||
62682a34 | 166 | { |
c34b1796 AL |
167 | let mut add_num = |x: i32| num += x; |
168 | ||
169 | add_num(5); | |
1a4d82fc | 170 | } |
c34b1796 AL |
171 | |
172 | assert_eq!(10, num); | |
1a4d82fc JJ |
173 | ``` |
174 | ||
c34b1796 | 175 | So in this case, our closure took a mutable reference to `num`, and then when |
bd371182 | 176 | we called `add_num`, it mutated the underlying value, as we’d expect. We also |
c34b1796 AL |
177 | needed to declare `add_num` as `mut` too, because we’re mutating its |
178 | environment. | |
1a4d82fc | 179 | |
bd371182 | 180 | If we change to a `move` closure, it’s different: |
c34b1796 AL |
181 | |
182 | ```rust | |
183 | let mut num = 5; | |
1a4d82fc | 184 | |
62682a34 | 185 | { |
c34b1796 | 186 | let mut add_num = move |x: i32| num += x; |
1a4d82fc | 187 | |
c34b1796 | 188 | add_num(5); |
1a4d82fc | 189 | } |
c34b1796 AL |
190 | |
191 | assert_eq!(5, num); | |
1a4d82fc JJ |
192 | ``` |
193 | ||
c34b1796 AL |
194 | We only get `5`. Rather than taking a mutable borrow out on our `num`, we took |
195 | ownership of a copy. | |
196 | ||
197 | Another way to think about `move` closures: they give a closure its own stack | |
198 | frame. Without `move`, a closure may be tied to the stack frame that created | |
199 | it, while a `move` closure is self-contained. This means that you cannot | |
200 | generally return a non-`move` closure from a function, for example. | |
201 | ||
b039eaaf SL |
202 | But before we talk about taking and returning closures, we should talk some |
203 | more about the way that closures are implemented. As a systems language, Rust | |
204 | gives you tons of control over what your code does, and closures are no | |
205 | different. | |
1a4d82fc | 206 | |
c34b1796 | 207 | # Closure implementation |
1a4d82fc | 208 | |
bd371182 AL |
209 | Rust’s implementation of closures is a bit different than other languages. They |
210 | are effectively syntax sugar for traits. You’ll want to make sure to have read | |
9cc50fc6 | 211 | the [traits][traits] section before this one, as well as the section on [trait |
9346a6ac | 212 | objects][trait-objects]. |
1a4d82fc | 213 | |
c34b1796 | 214 | [traits]: traits.html |
9346a6ac | 215 | [trait-objects]: trait-objects.html |
1a4d82fc | 216 | |
c34b1796 AL |
217 | Got all that? Good. |
218 | ||
219 | The key to understanding how closures work under the hood is something a bit | |
220 | strange: Using `()` to call a function, like `foo()`, is an overloadable | |
221 | operator. From this, everything else clicks into place. In Rust, we use the | |
222 | trait system to overload operators. Calling functions is no different. We have | |
223 | three separate traits to overload with: | |
224 | ||
225 | ```rust | |
5bcae85e | 226 | # #![feature(unboxed_closures)] |
c34b1796 AL |
227 | # mod foo { |
228 | pub trait Fn<Args> : FnMut<Args> { | |
229 | extern "rust-call" fn call(&self, args: Args) -> Self::Output; | |
1a4d82fc JJ |
230 | } |
231 | ||
c34b1796 AL |
232 | pub trait FnMut<Args> : FnOnce<Args> { |
233 | extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output; | |
234 | } | |
235 | ||
236 | pub trait FnOnce<Args> { | |
237 | type Output; | |
1a4d82fc | 238 | |
c34b1796 | 239 | extern "rust-call" fn call_once(self, args: Args) -> Self::Output; |
1a4d82fc | 240 | } |
c34b1796 | 241 | # } |
1a4d82fc JJ |
242 | ``` |
243 | ||
bd371182 | 244 | You’ll notice a few differences between these traits, but a big one is `self`: |
c34b1796 | 245 | `Fn` takes `&self`, `FnMut` takes `&mut self`, and `FnOnce` takes `self`. This |
bd371182 | 246 | covers all three kinds of `self` via the usual method call syntax. But we’ve |
c34b1796 AL |
247 | split them up into three traits, rather than having a single one. This gives us |
248 | a large amount of control over what kind of closures we can take. | |
1a4d82fc | 249 | |
c34b1796 AL |
250 | The `|| {}` syntax for closures is sugar for these three traits. Rust will |
251 | generate a struct for the environment, `impl` the appropriate trait, and then | |
252 | use it. | |
253 | ||
254 | # Taking closures as arguments | |
255 | ||
256 | Now that we know that closures are traits, we already know how to accept and | |
9cc50fc6 | 257 | return closures: the same as any other trait! |
c34b1796 AL |
258 | |
259 | This also means that we can choose static vs dynamic dispatch as well. First, | |
bd371182 | 260 | let’s write a function which takes something callable, calls it, and returns |
c34b1796 AL |
261 | the result: |
262 | ||
263 | ```rust | |
264 | fn call_with_one<F>(some_closure: F) -> i32 | |
9e0c209e | 265 | where F: Fn(i32) -> i32 { |
c34b1796 AL |
266 | |
267 | some_closure(1) | |
268 | } | |
1a4d82fc | 269 | |
c34b1796 | 270 | let answer = call_with_one(|x| x + 2); |
1a4d82fc | 271 | |
c34b1796 | 272 | assert_eq!(3, answer); |
1a4d82fc JJ |
273 | ``` |
274 | ||
9cc50fc6 | 275 | We pass our closure, `|x| x + 2`, to `call_with_one`. It does what it |
c34b1796 | 276 | suggests: it calls the closure, giving it `1` as an argument. |
1a4d82fc | 277 | |
bd371182 | 278 | Let’s examine the signature of `call_with_one` in more depth: |
1a4d82fc | 279 | |
c34b1796 AL |
280 | ```rust |
281 | fn call_with_one<F>(some_closure: F) -> i32 | |
9e0c209e | 282 | # where F: Fn(i32) -> i32 { |
c34b1796 | 283 | # some_closure(1) } |
1a4d82fc JJ |
284 | ``` |
285 | ||
c34b1796 | 286 | We take one parameter, and it has the type `F`. We also return a `i32`. This part |
bd371182 | 287 | isn’t interesting. The next part is: |
1a4d82fc | 288 | |
c34b1796 AL |
289 | ```rust |
290 | # fn call_with_one<F>(some_closure: F) -> i32 | |
9e0c209e | 291 | where F: Fn(i32) -> i32 { |
c34b1796 AL |
292 | # some_closure(1) } |
293 | ``` | |
294 | ||
5bcae85e SL |
295 | Because `Fn` is a trait, we can use it as a bound for our generic type. In |
296 | this case, our closure takes a `i32` as an argument and returns an `i32`, and | |
297 | so the generic bound we use is `Fn(i32) -> i32`. | |
1a4d82fc | 298 | |
bd371182 AL |
299 | There’s one other key point here: because we’re bounding a generic with a |
300 | trait, this will get monomorphized, and therefore, we’ll be doing static | |
301 | dispatch into the closure. That’s pretty neat. In many languages, closures are | |
c34b1796 AL |
302 | inherently heap allocated, and will always involve dynamic dispatch. In Rust, |
303 | we can stack allocate our closure environment, and statically dispatch the | |
304 | call. This happens quite often with iterators and their adapters, which often | |
305 | take closures as arguments. | |
1a4d82fc | 306 | |
c34b1796 AL |
307 | Of course, if we want dynamic dispatch, we can get that too. A trait object |
308 | handles this case, as usual: | |
1a4d82fc | 309 | |
c34b1796 AL |
310 | ```rust |
311 | fn call_with_one(some_closure: &Fn(i32) -> i32) -> i32 { | |
312 | some_closure(1) | |
1a4d82fc | 313 | } |
c34b1796 AL |
314 | |
315 | let answer = call_with_one(&|x| x + 2); | |
316 | ||
317 | assert_eq!(3, answer); | |
1a4d82fc JJ |
318 | ``` |
319 | ||
c34b1796 AL |
320 | Now we take a trait object, a `&Fn`. And we have to make a reference |
321 | to our closure when we pass it to `call_with_one`, so we use `&||`. | |
1a4d82fc | 322 | |
a7813a04 XL |
323 | A quick note about closures that use explicit lifetimes. Sometimes you might have a closure |
324 | that takes a reference like so: | |
325 | ||
3157f602 | 326 | ```rust |
a7813a04 XL |
327 | fn call_with_ref<F>(some_closure:F) -> i32 |
328 | where F: Fn(&i32) -> i32 { | |
329 | ||
330 | let mut value = 0; | |
331 | some_closure(&value) | |
332 | } | |
333 | ``` | |
334 | ||
335 | Normally you can specify the lifetime of the parameter to our closure. We | |
336 | could annotate it on the function declaration: | |
337 | ||
3157f602 XL |
338 | ```rust,ignore |
339 | fn call_with_ref<'a, F>(some_closure:F) -> i32 | |
5bcae85e | 340 | where F: Fn(&'a i32) -> i32 { |
a7813a04 XL |
341 | ``` |
342 | ||
9e0c209e | 343 | However this presents a problem in our case. When you specify the explicit |
a7813a04 XL |
344 | lifetime on a function it binds that lifetime to the *entire* scope of the function |
345 | instead of just the invocation scope of our closure. This means that the borrow checker | |
346 | will see a mutable reference in the same lifetime as our immutable reference and fail | |
347 | to compile. | |
348 | ||
349 | In order to say that we only need the lifetime to be valid for the invocation scope | |
350 | of the closure we can use Higher-Ranked Trait Bounds with the `for<...>` syntax: | |
351 | ||
352 | ```ignore | |
353 | fn call_with_ref<F>(some_closure:F) -> i32 | |
5bcae85e | 354 | where F: for<'a> Fn(&'a i32) -> i32 { |
a7813a04 XL |
355 | ``` |
356 | ||
3157f602 | 357 | This lets the Rust compiler find the minimum lifetime to invoke our closure and |
5bcae85e | 358 | satisfy the borrow checker's rules. Our function then compiles and executes as we |
a7813a04 XL |
359 | expect. |
360 | ||
3157f602 | 361 | ```rust |
a7813a04 XL |
362 | fn call_with_ref<F>(some_closure:F) -> i32 |
363 | where F: for<'a> Fn(&'a i32) -> i32 { | |
364 | ||
365 | let mut value = 0; | |
366 | some_closure(&value) | |
367 | } | |
368 | ``` | |
369 | ||
e9174d1e SL |
370 | # Function pointers and closures |
371 | ||
372 | A function pointer is kind of like a closure that has no environment. As such, | |
373 | you can pass a function pointer to any function expecting a closure argument, | |
374 | and it will work: | |
375 | ||
376 | ```rust | |
377 | fn call_with_one(some_closure: &Fn(i32) -> i32) -> i32 { | |
378 | some_closure(1) | |
379 | } | |
380 | ||
381 | fn add_one(i: i32) -> i32 { | |
382 | i + 1 | |
383 | } | |
384 | ||
385 | let f = add_one; | |
386 | ||
387 | let answer = call_with_one(&f); | |
388 | ||
389 | assert_eq!(2, answer); | |
390 | ``` | |
391 | ||
392 | In this example, we don’t strictly need the intermediate variable `f`, | |
393 | the name of the function works just fine too: | |
394 | ||
a7813a04 | 395 | ```rust,ignore |
e9174d1e SL |
396 | let answer = call_with_one(&add_one); |
397 | ``` | |
398 | ||
c34b1796 | 399 | # Returning closures |
1a4d82fc | 400 | |
c34b1796 AL |
401 | It’s very common for functional-style code to return closures in various |
402 | situations. If you try to return a closure, you may run into an error. At | |
bd371182 | 403 | first, it may seem strange, but we’ll figure it out. Here’s how you’d probably |
c34b1796 | 404 | try to return a closure from a function: |
1a4d82fc | 405 | |
c34b1796 | 406 | ```rust,ignore |
62682a34 SL |
407 | fn factory() -> (Fn(i32) -> i32) { |
408 | let num = 5; | |
1a4d82fc | 409 | |
62682a34 | 410 | |x| x + num |
1a4d82fc JJ |
411 | } |
412 | ||
c34b1796 AL |
413 | let f = factory(); |
414 | ||
62682a34 SL |
415 | let answer = f(1); |
416 | assert_eq!(6, answer); | |
1a4d82fc JJ |
417 | ``` |
418 | ||
c34b1796 AL |
419 | This gives us these long, related errors: |
420 | ||
421 | ```text | |
54a0048b | 422 | error: the trait bound `core::ops::Fn(i32) -> i32 : core::marker::Sized` is not satisfied [E0277] |
62682a34 SL |
423 | fn factory() -> (Fn(i32) -> i32) { |
424 | ^~~~~~~~~~~~~~~~ | |
425 | note: `core::ops::Fn(i32) -> i32` does not have a constant size known at compile-time | |
426 | fn factory() -> (Fn(i32) -> i32) { | |
427 | ^~~~~~~~~~~~~~~~ | |
54a0048b | 428 | error: the trait bound `core::ops::Fn(i32) -> i32 : core::marker::Sized` is not satisfied [E0277] |
62682a34 SL |
429 | let f = factory(); |
430 | ^ | |
431 | note: `core::ops::Fn(i32) -> i32` does not have a constant size known at compile-time | |
432 | let f = factory(); | |
433 | ^ | |
c34b1796 | 434 | ``` |
1a4d82fc | 435 | |
c34b1796 AL |
436 | In order to return something from a function, Rust needs to know what |
437 | size the return type is. But since `Fn` is a trait, it could be various | |
438 | things of various sizes: many different types can implement `Fn`. An easy | |
439 | way to give something a size is to take a reference to it, as references | |
bd371182 | 440 | have a known size. So we’d write this: |
1a4d82fc | 441 | |
c34b1796 | 442 | ```rust,ignore |
62682a34 SL |
443 | fn factory() -> &(Fn(i32) -> i32) { |
444 | let num = 5; | |
c34b1796 | 445 | |
62682a34 | 446 | |x| x + num |
1a4d82fc | 447 | } |
c34b1796 AL |
448 | |
449 | let f = factory(); | |
450 | ||
62682a34 SL |
451 | let answer = f(1); |
452 | assert_eq!(6, answer); | |
c34b1796 AL |
453 | ``` |
454 | ||
455 | But we get another error: | |
456 | ||
457 | ```text | |
458 | error: missing lifetime specifier [E0106] | |
459 | fn factory() -> &(Fn(i32) -> i32) { | |
460 | ^~~~~~~~~~~~~~~~~ | |
1a4d82fc JJ |
461 | ``` |
462 | ||
c34b1796 | 463 | Right. Because we have a reference, we need to give it a lifetime. But |
b039eaaf SL |
464 | our `factory()` function takes no arguments, so |
465 | [elision](lifetimes.html#lifetime-elision) doesn’t kick in here. Then what | |
466 | choices do we have? Try `'static`: | |
1a4d82fc | 467 | |
c34b1796 AL |
468 | ```rust,ignore |
469 | fn factory() -> &'static (Fn(i32) -> i32) { | |
470 | let num = 5; | |
85aaf69f | 471 | |
c34b1796 | 472 | |x| x + num |
85aaf69f SL |
473 | } |
474 | ||
c34b1796 AL |
475 | let f = factory(); |
476 | ||
477 | let answer = f(1); | |
478 | assert_eq!(6, answer); | |
479 | ``` | |
480 | ||
481 | But we get another error: | |
482 | ||
483 | ```text | |
484 | error: mismatched types: | |
485 | expected `&'static core::ops::Fn(i32) -> i32`, | |
b039eaaf | 486 | found `[closure@<anon>:7:9: 7:20]` |
c34b1796 AL |
487 | (expected &-ptr, |
488 | found closure) [E0308] | |
489 | |x| x + num | |
490 | ^~~~~~~~~~~ | |
491 | ||
492 | ``` | |
493 | ||
bd371182 | 494 | This error is letting us know that we don’t have a `&'static Fn(i32) -> i32`, |
b039eaaf | 495 | we have a `[closure@<anon>:7:9: 7:20]`. Wait, what? |
c34b1796 AL |
496 | |
497 | Because each closure generates its own environment `struct` and implementation | |
9cc50fc6 | 498 | of `Fn` and friends, these types are anonymous. They exist solely for |
b039eaaf | 499 | this closure. So Rust shows them as `closure@<anon>`, rather than some |
c34b1796 AL |
500 | autogenerated name. |
501 | ||
b039eaaf SL |
502 | The error also points out that the return type is expected to be a reference, |
503 | but what we are trying to return is not. Further, we cannot directly assign a | |
504 | `'static` lifetime to an object. So we'll take a different approach and return | |
505 | a ‘trait object’ by `Box`ing up the `Fn`. This _almost_ works: | |
c34b1796 AL |
506 | |
507 | ```rust,ignore | |
508 | fn factory() -> Box<Fn(i32) -> i32> { | |
509 | let num = 5; | |
510 | ||
511 | Box::new(|x| x + num) | |
85aaf69f | 512 | } |
c34b1796 AL |
513 | # fn main() { |
514 | let f = factory(); | |
515 | ||
516 | let answer = f(1); | |
517 | assert_eq!(6, answer); | |
518 | # } | |
85aaf69f SL |
519 | ``` |
520 | ||
b039eaaf | 521 | There’s just one last problem: |
85aaf69f | 522 | |
c34b1796 | 523 | ```text |
62682a34 SL |
524 | error: closure may outlive the current function, but it borrows `num`, |
525 | which is owned by the current function [E0373] | |
c34b1796 AL |
526 | Box::new(|x| x + num) |
527 | ^~~~~~~~~~~ | |
528 | ``` | |
529 | ||
b039eaaf SL |
530 | Well, as we discussed before, closures borrow their environment. And in this |
531 | case, our environment is based on a stack-allocated `5`, the `num` variable | |
532 | binding. So the borrow has a lifetime of the stack frame. So if we returned | |
533 | this closure, the function call would be over, the stack frame would go away, | |
534 | and our closure is capturing an environment of garbage memory! With one last | |
535 | fix, we can make this work: | |
85aaf69f | 536 | |
c34b1796 AL |
537 | ```rust |
538 | fn factory() -> Box<Fn(i32) -> i32> { | |
539 | let num = 5; | |
85aaf69f | 540 | |
c34b1796 AL |
541 | Box::new(move |x| x + num) |
542 | } | |
a7813a04 | 543 | fn main() { |
c34b1796 AL |
544 | let f = factory(); |
545 | ||
546 | let answer = f(1); | |
547 | assert_eq!(6, answer); | |
a7813a04 | 548 | } |
c34b1796 | 549 | ``` |
85aaf69f | 550 | |
c34b1796 | 551 | By making the inner closure a `move Fn`, we create a new stack frame for our |
54a0048b | 552 | closure. By `Box`ing it up, we’ve given it a known size, allowing it to |
c34b1796 | 553 | escape our stack frame. |