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