]> git.lizzy.rs Git - rust.git/blob - src/doc/book/closures.md
d332cac7d8d16c76bed6b7bad805c1c389239feb
[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][traits] section before this one, as well as the section 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 # #![feature(unboxed_closures)]
227 # mod foo {
228 pub trait Fn<Args> : FnMut<Args> {
229     extern "rust-call" fn call(&self, args: Args) -> Self::Output;
230 }
231
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;
238
239     extern "rust-call" fn call_once(self, args: Args) -> Self::Output;
240 }
241 # }
242 ```
243
244 You’ll notice a few differences between these traits, but a big one is `self`:
245 `Fn` takes `&self`, `FnMut` takes `&mut self`, and `FnOnce` takes `self`. This
246 covers all three kinds of `self` via the usual method call syntax. But we’ve
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.
249
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
257 return closures: the same as any other trait!
258
259 This also means that we can choose static vs dynamic dispatch as well. First,
260 let’s write a function which takes something callable, calls it, and returns
261 the result:
262
263 ```rust
264 fn call_with_one<F>(some_closure: F) -> i32
265     where F: Fn(i32) -> i32 {
266
267     some_closure(1)
268 }
269
270 let answer = call_with_one(|x| x + 2);
271
272 assert_eq!(3, answer);
273 ```
274
275 We pass our closure, `|x| x + 2`, to `call_with_one`. It does what it
276 suggests: it calls the closure, giving it `1` as an argument.
277
278 Let’s examine the signature of `call_with_one` in more depth:
279
280 ```rust
281 fn call_with_one<F>(some_closure: F) -> i32
282 #    where F: Fn(i32) -> i32 {
283 #    some_closure(1) }
284 ```
285
286 We take one parameter, and it has the type `F`. We also return a `i32`. This part
287 isn’t interesting. The next part is:
288
289 ```rust
290 # fn call_with_one<F>(some_closure: F) -> i32
291     where F: Fn(i32) -> i32 {
292 #   some_closure(1) }
293 ```
294
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`.
298
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
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.
306
307 Of course, if we want dynamic dispatch, we can get that too. A trait object
308 handles this case, as usual:
309
310 ```rust
311 fn call_with_one(some_closure: &Fn(i32) -> i32) -> i32 {
312     some_closure(1)
313 }
314
315 let answer = call_with_one(&|x| x + 2);
316
317 assert_eq!(3, answer);
318 ```
319
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 `&||`.
322
323 A quick note about closures that use explicit lifetimes. Sometimes you might have a closure
324 that takes a reference like so:
325
326 ```rust
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
338 ```rust,ignore
339 fn call_with_ref<'a, F>(some_closure:F) -> i32
340     where F: Fn(&'a i32) -> i32 {
341 ```
342
343 However this presents a problem with in our case. When you specify the explicit
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
354     where F: for<'a> Fn(&'a i32) -> i32 {
355 ```
356
357 This lets the Rust compiler find the minimum lifetime to invoke our closure and
358 satisfy the borrow checker's rules. Our function then compiles and executes as we
359 expect.
360
361 ```rust
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
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
395 ```rust,ignore
396 let answer = call_with_one(&add_one);
397 ```
398
399 # Returning closures
400
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
403 first, it may seem strange, but we’ll figure it out. Here’s how you’d probably
404 try to return a closure from a function:
405
406 ```rust,ignore
407 fn factory() -> (Fn(i32) -> i32) {
408     let num = 5;
409
410     |x| x + num
411 }
412
413 let f = factory();
414
415 let answer = f(1);
416 assert_eq!(6, answer);
417 ```
418
419 This gives us these long, related errors:
420
421 ```text
422 error: the trait bound `core::ops::Fn(i32) -> i32 : core::marker::Sized` is not satisfied [E0277]
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                 ^~~~~~~~~~~~~~~~
428 error: the trait bound `core::ops::Fn(i32) -> i32 : core::marker::Sized` is not satisfied [E0277]
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     ^
434 ```
435
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
440 have a known size. So we’d write this:
441
442 ```rust,ignore
443 fn factory() -> &(Fn(i32) -> i32) {
444     let num = 5;
445
446     |x| x + num
447 }
448
449 let f = factory();
450
451 let answer = f(1);
452 assert_eq!(6, answer);
453 ```
454
455 But we get another error:
456
457 ```text
458 error: missing lifetime specifier [E0106]
459 fn factory() -> &(Fn(i32) -> i32) {
460                 ^~~~~~~~~~~~~~~~~
461 ```
462
463 Right. Because we have a reference, we need to give it a lifetime. But
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`:
467
468 ```rust,ignore
469 fn factory() -> &'static (Fn(i32) -> i32) {
470     let num = 5;
471
472     |x| x + num
473 }
474
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`,
486     found `[closure@<anon>:7:9: 7:20]`
487 (expected &-ptr,
488     found closure) [E0308]
489          |x| x + num
490          ^~~~~~~~~~~
491
492 ```
493
494 This error is letting us know that we don’t have a `&'static Fn(i32) -> i32`,
495 we have a `[closure@<anon>:7:9: 7:20]`. Wait, what?
496
497 Because each closure generates its own environment `struct` and implementation
498 of `Fn` and friends, these types are anonymous. They exist solely for
499 this closure. So Rust shows them as `closure@<anon>`, rather than some
500 autogenerated name.
501
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:
506
507 ```rust,ignore
508 fn factory() -> Box<Fn(i32) -> i32> {
509     let num = 5;
510
511     Box::new(|x| x + num)
512 }
513 # fn main() {
514 let f = factory();
515
516 let answer = f(1);
517 assert_eq!(6, answer);
518 # }
519 ```
520
521 There’s just one last problem:
522
523 ```text
524 error: closure may outlive the current function, but it borrows `num`,
525 which is owned by the current function [E0373]
526 Box::new(|x| x + num)
527          ^~~~~~~~~~~
528 ```
529
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:
536
537 ```rust
538 fn factory() -> Box<Fn(i32) -> i32> {
539     let num = 5;
540
541     Box::new(move |x| x + num)
542 }
543 fn main() {
544 let f = factory();
545
546 let answer = f(1);
547 assert_eq!(6, answer);
548 }
549 ```
550
551 By making the inner closure a `move Fn`, we create a new stack frame for our
552 closure. By `Box`ing it up, we’ve given it a known size, allowing it to
553 escape our stack frame.