]> git.lizzy.rs Git - rust.git/blob - src/doc/book/closures.md
Auto merge of #30145 - petrochenkov:hyg, r=nrc
[rust.git] / src / doc / book / closures.md
1 % Closures
2
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.
8
9 # Syntax
10
11 Closures look like this:
12
13 ```rust
14 let plus_one = |x: i32| x + 1;
15
16 assert_eq!(2, plus_one(1));
17 ```
18
19 We create a binding, `plus_one`, and assign it to a closure. The closure’s
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
37 You’ll notice a few things about closures that are a bit different from regular
38 named functions defined with `fn`. The first is that we did not need to
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
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.
54
55 The second is that the syntax is similar, but a bit different. I’ve added
56 spaces here for easier comparison:
57
58 ```rust
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  ;
62 ```
63
64 Small differences, but they’re similar.
65
66 # Closures and their environment
67
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:
70
71 ```rust
72 let num = 5;
73 let plus_num = |x: i32| x + num;
74
75 assert_eq!(10, plus_num(5));
76 ```
77
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;
85
86 let y = &mut num;
87 ```
88
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
101 fn main() {
102     let mut num = 5;
103     let plus_num = |x| x + num;
104
105     let y = &mut num;
106 }
107 ^
108 ```
109
110 A verbose yet helpful error message! As it says, we can’t take a mutable borrow
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
120
121 let y = &mut num;
122 ```
123
124 If your closure requires it, however, Rust will take ownership and move
125 the environment instead. This doesn’t work:
126
127 ```rust,ignore
128 let nums = vec![1, 2, 3];
129
130 let takes_nums = || nums;
131
132 println!("{:?}", nums);
133 ```
134
135 We get this error:
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;
141                  ^~~~~~~
142 ```
143
144 `Vec<T>` has ownership over its contents, and therefore, when we refer to it
145 in our closure, we have to take ownership of `nums`. It’s the same as if we’d
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:
152
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
161 of `num`. So what’s the difference?
162
163 ```rust
164 let mut num = 5;
165
166 {
167     let mut add_num = |x: i32| num += x;
168
169     add_num(5);
170 }
171
172 assert_eq!(10, num);
173 ```
174
175 So in this case, our closure took a mutable reference to `num`, and then when
176 we called `add_num`, it mutated the underlying value, as we’d expect. We also
177 needed to declare `add_num` as `mut` too, because we’re mutating its
178 environment.
179
180 If we change to a `move` closure, it’s different:
181
182 ```rust
183 let mut num = 5;
184
185 {
186     let mut add_num = move |x: i32| num += x;
187
188     add_num(5);
189 }
190
191 assert_eq!(5, num);
192 ```
193
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
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.
206
207 # Closure implementation
208
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
211 the [traits chapter][traits] before this one, as well as the chapter on [trait
212 objects][trait-objects].
213
214 [traits]: traits.html
215 [trait-objects]: trait-objects.html
216
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
226 # mod foo {
227 pub trait Fn<Args> : FnMut<Args> {
228     extern "rust-call" fn call(&self, args: Args) -> Self::Output;
229 }
230
231 pub trait FnMut<Args> : FnOnce<Args> {
232     extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output;
233 }
234
235 pub trait FnOnce<Args> {
236     type Output;
237
238     extern "rust-call" fn call_once(self, args: Args) -> Self::Output;
239 }
240 # }
241 ```
242
243 You’ll notice a few differences between these traits, but a big one is `self`:
244 `Fn` takes `&self`, `FnMut` takes `&mut self`, and `FnOnce` takes `self`. This
245 covers all three kinds of `self` via the usual method call syntax. But we’ve
246 split them up into three traits, rather than having a single one. This gives us
247 a large amount of control over what kind of closures we can take.
248
249 The `|| {}` syntax for closures is sugar for these three traits. Rust will
250 generate a struct for the environment, `impl` the appropriate trait, and then
251 use it.
252
253 # Taking closures as arguments
254
255 Now that we know that closures are traits, we already know how to accept and
256 return closures: just like any other trait!
257
258 This also means that we can choose static vs dynamic dispatch as well. First,
259 let’s write a function which takes something callable, calls it, and returns
260 the result:
261
262 ```rust
263 fn call_with_one<F>(some_closure: F) -> i32
264     where F : Fn(i32) -> i32 {
265
266     some_closure(1)
267 }
268
269 let answer = call_with_one(|x| x + 2);
270
271 assert_eq!(3, answer);
272 ```
273
274 We pass our closure, `|x| x + 2`, to `call_with_one`. It just does what it
275 suggests: it calls the closure, giving it `1` as an argument.
276
277 Let’s examine the signature of `call_with_one` in more depth:
278
279 ```rust
280 fn call_with_one<F>(some_closure: F) -> i32
281 #    where F : Fn(i32) -> i32 {
282 #    some_closure(1) }
283 ```
284
285 We take one parameter, and it has the type `F`. We also return a `i32`. This part
286 isn’t interesting. The next part is:
287
288 ```rust
289 # fn call_with_one<F>(some_closure: F) -> i32
290     where F : Fn(i32) -> i32 {
291 #   some_closure(1) }
292 ```
293
294 Because `Fn` is a trait, we can bound our generic with it. In this case, our
295 closure takes a `i32` as an argument and returns an `i32`, and so the generic
296 bound we use is `Fn(i32) -> i32`.
297
298 There’s one other key point here: because we’re bounding a generic with a
299 trait, this will get monomorphized, and therefore, we’ll be doing static
300 dispatch into the closure. That’s pretty neat. In many languages, closures are
301 inherently heap allocated, and will always involve dynamic dispatch. In Rust,
302 we can stack allocate our closure environment, and statically dispatch the
303 call. This happens quite often with iterators and their adapters, which often
304 take closures as arguments.
305
306 Of course, if we want dynamic dispatch, we can get that too. A trait object
307 handles this case, as usual:
308
309 ```rust
310 fn call_with_one(some_closure: &Fn(i32) -> i32) -> i32 {
311     some_closure(1)
312 }
313
314 let answer = call_with_one(&|x| x + 2);
315
316 assert_eq!(3, answer);
317 ```
318
319 Now we take a trait object, a `&Fn`. And we have to make a reference
320 to our closure when we pass it to `call_with_one`, so we use `&||`.
321
322 # Function pointers and closures
323
324 A function pointer is kind of like a closure that has no environment. As such,
325 you can pass a function pointer to any function expecting a closure argument,
326 and it will work:
327
328 ```rust
329 fn call_with_one(some_closure: &Fn(i32) -> i32) -> i32 {
330     some_closure(1)
331 }
332
333 fn add_one(i: i32) -> i32 {
334     i + 1
335 }
336
337 let f = add_one;
338
339 let answer = call_with_one(&f);
340
341 assert_eq!(2, answer);
342 ```
343
344 In this example, we don’t strictly need the intermediate variable `f`,
345 the name of the function works just fine too:
346
347 ```ignore
348 let answer = call_with_one(&add_one);
349 ```
350
351 # Returning closures
352
353 It’s very common for functional-style code to return closures in various
354 situations. If you try to return a closure, you may run into an error. At
355 first, it may seem strange, but we’ll figure it out. Here’s how you’d probably
356 try to return a closure from a function:
357
358 ```rust,ignore
359 fn factory() -> (Fn(i32) -> i32) {
360     let num = 5;
361
362     |x| x + num
363 }
364
365 let f = factory();
366
367 let answer = f(1);
368 assert_eq!(6, answer);
369 ```
370
371 This gives us these long, related errors:
372
373 ```text
374 error: the trait `core::marker::Sized` is not implemented for the type
375 `core::ops::Fn(i32) -> i32` [E0277]
376 fn factory() -> (Fn(i32) -> i32) {
377                 ^~~~~~~~~~~~~~~~
378 note: `core::ops::Fn(i32) -> i32` does not have a constant size known at compile-time
379 fn factory() -> (Fn(i32) -> i32) {
380                 ^~~~~~~~~~~~~~~~
381 error: the trait `core::marker::Sized` is not implemented for the type `core::ops::Fn(i32) -> i32` [E0277]
382 let f = factory();
383     ^
384 note: `core::ops::Fn(i32) -> i32` does not have a constant size known at compile-time
385 let f = factory();
386     ^
387 ```
388
389 In order to return something from a function, Rust needs to know what
390 size the return type is. But since `Fn` is a trait, it could be various
391 things of various sizes: many different types can implement `Fn`. An easy
392 way to give something a size is to take a reference to it, as references
393 have a known size. So we’d write this:
394
395 ```rust,ignore
396 fn factory() -> &(Fn(i32) -> i32) {
397     let num = 5;
398
399     |x| x + num
400 }
401
402 let f = factory();
403
404 let answer = f(1);
405 assert_eq!(6, answer);
406 ```
407
408 But we get another error:
409
410 ```text
411 error: missing lifetime specifier [E0106]
412 fn factory() -> &(Fn(i32) -> i32) {
413                 ^~~~~~~~~~~~~~~~~
414 ```
415
416 Right. Because we have a reference, we need to give it a lifetime. But
417 our `factory()` function takes no arguments, so
418 [elision](lifetimes.html#lifetime-elision) doesn’t kick in here. Then what
419 choices do we have? Try `'static`:
420
421 ```rust,ignore
422 fn factory() -> &'static (Fn(i32) -> i32) {
423     let num = 5;
424
425     |x| x + num
426 }
427
428 let f = factory();
429
430 let answer = f(1);
431 assert_eq!(6, answer);
432 ```
433
434 But we get another error:
435
436 ```text
437 error: mismatched types:
438  expected `&'static core::ops::Fn(i32) -> i32`,
439     found `[closure@<anon>:7:9: 7:20]`
440 (expected &-ptr,
441     found closure) [E0308]
442          |x| x + num
443          ^~~~~~~~~~~
444
445 ```
446
447 This error is letting us know that we don’t have a `&'static Fn(i32) -> i32`,
448 we have a `[closure@<anon>:7:9: 7:20]`. Wait, what?
449
450 Because each closure generates its own environment `struct` and implementation
451 of `Fn` and friends, these types are anonymous. They exist just solely for
452 this closure. So Rust shows them as `closure@<anon>`, rather than some
453 autogenerated name.
454
455 The error also points out that the return type is expected to be a reference,
456 but what we are trying to return is not. Further, we cannot directly assign a
457 `'static` lifetime to an object. So we'll take a different approach and return
458 a ‘trait object’ by `Box`ing up the `Fn`. This _almost_ works:
459
460 ```rust,ignore
461 fn factory() -> Box<Fn(i32) -> i32> {
462     let num = 5;
463
464     Box::new(|x| x + num)
465 }
466 # fn main() {
467 let f = factory();
468
469 let answer = f(1);
470 assert_eq!(6, answer);
471 # }
472 ```
473
474 There’s just one last problem:
475
476 ```text
477 error: closure may outlive the current function, but it borrows `num`,
478 which is owned by the current function [E0373]
479 Box::new(|x| x + num)
480          ^~~~~~~~~~~
481 ```
482
483 Well, as we discussed before, closures borrow their environment. And in this
484 case, our environment is based on a stack-allocated `5`, the `num` variable
485 binding. So the borrow has a lifetime of the stack frame. So if we returned
486 this closure, the function call would be over, the stack frame would go away,
487 and our closure is capturing an environment of garbage memory! With one last
488 fix, we can make this work:
489
490 ```rust
491 fn factory() -> Box<Fn(i32) -> i32> {
492     let num = 5;
493
494     Box::new(move |x| x + num)
495 }
496 # fn main() {
497 let f = factory();
498
499 let answer = f(1);
500 assert_eq!(6, answer);
501 # }
502 ```
503
504 By making the inner closure a `move Fn`, we create a new stack frame for our
505 closure. By `Box`ing it up, we’ve given it a known size, and allowing it to
506 escape our stack frame.