]> git.proxmox.com Git - rustc.git/blob - src/doc/book/closures.md
New upstream version 1.16.0+dfsg1
[rustc.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 an `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 an `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 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 in our case. When a function has an explicit
344 lifetime parameter, that lifetime must be at least as long as the *entire*
345 call to that function. The borrow checker will complain that `value` doesn't
346 live long enough, because it is only in scope after its declaration inside the
347 function body.
348
349 What we need is a closure that can borrow its argument only for its own
350 invocation scope, not for the outer function's scope. In order to say that,
351 we can use Higher-Ranked Trait Bounds with the `for<...>` syntax:
352
353 ```ignore
354 fn call_with_ref<F>(some_closure:F) -> i32
355 where F: for<'a> Fn(&'a i32) -> i32 {
356 ```
357
358 This lets the Rust compiler find the minimum lifetime to invoke our closure and
359 satisfy the borrow checker's rules. Our function then compiles and executes as we
360 expect.
361
362 ```rust
363 fn call_with_ref<F>(some_closure:F) -> i32
364 where F: for<'a> Fn(&'a i32) -> i32 {
365
366 let value = 0;
367 some_closure(&value)
368 }
369 ```
370
371 # Function pointers and closures
372
373 A function pointer is kind of like a closure that has no environment. As such,
374 you can pass a function pointer to any function expecting a closure argument,
375 and it will work:
376
377 ```rust
378 fn call_with_one(some_closure: &Fn(i32) -> i32) -> i32 {
379 some_closure(1)
380 }
381
382 fn add_one(i: i32) -> i32 {
383 i + 1
384 }
385
386 let f = add_one;
387
388 let answer = call_with_one(&f);
389
390 assert_eq!(2, answer);
391 ```
392
393 In this example, we don’t strictly need the intermediate variable `f`,
394 the name of the function works just fine too:
395
396 ```rust,ignore
397 let answer = call_with_one(&add_one);
398 ```
399
400 # Returning closures
401
402 It’s very common for functional-style code to return closures in various
403 situations. If you try to return a closure, you may run into an error. At
404 first, it may seem strange, but we’ll figure it out. Here’s how you’d probably
405 try to return a closure from a function:
406
407 ```rust,ignore
408 fn factory() -> (Fn(i32) -> i32) {
409 let num = 5;
410
411 |x| x + num
412 }
413
414 let f = factory();
415
416 let answer = f(1);
417 assert_eq!(6, answer);
418 ```
419
420 This gives us these long, related errors:
421
422 ```text
423 error: the trait bound `core::ops::Fn(i32) -> i32 : core::marker::Sized` is not satisfied [E0277]
424 fn factory() -> (Fn(i32) -> i32) {
425 ^~~~~~~~~~~~~~~~
426 note: `core::ops::Fn(i32) -> i32` does not have a constant size known at compile-time
427 fn factory() -> (Fn(i32) -> i32) {
428 ^~~~~~~~~~~~~~~~
429 error: the trait bound `core::ops::Fn(i32) -> i32 : core::marker::Sized` is not satisfied [E0277]
430 let f = factory();
431 ^
432 note: `core::ops::Fn(i32) -> i32` does not have a constant size known at compile-time
433 let f = factory();
434 ^
435 ```
436
437 In order to return something from a function, Rust needs to know what
438 size the return type is. But since `Fn` is a trait, it could be various
439 things of various sizes: many different types can implement `Fn`. An easy
440 way to give something a size is to take a reference to it, as references
441 have a known size. So we’d write this:
442
443 ```rust,ignore
444 fn factory() -> &(Fn(i32) -> i32) {
445 let num = 5;
446
447 |x| x + num
448 }
449
450 let f = factory();
451
452 let answer = f(1);
453 assert_eq!(6, answer);
454 ```
455
456 But we get another error:
457
458 ```text
459 error: missing lifetime specifier [E0106]
460 fn factory() -> &(Fn(i32) -> i32) {
461 ^~~~~~~~~~~~~~~~~
462 ```
463
464 Right. Because we have a reference, we need to give it a lifetime. But
465 our `factory()` function takes no arguments, so
466 [elision](lifetimes.html#lifetime-elision) doesn’t kick in here. Then what
467 choices do we have? Try `'static`:
468
469 ```rust,ignore
470 fn factory() -> &'static (Fn(i32) -> i32) {
471 let num = 5;
472
473 |x| x + num
474 }
475
476 let f = factory();
477
478 let answer = f(1);
479 assert_eq!(6, answer);
480 ```
481
482 But we get another error:
483
484 ```text
485 error: mismatched types:
486 expected `&'static core::ops::Fn(i32) -> i32`,
487 found `[closure@<anon>:7:9: 7:20]`
488 (expected &-ptr,
489 found closure) [E0308]
490 |x| x + num
491 ^~~~~~~~~~~
492
493 ```
494
495 This error is letting us know that we don’t have a `&'static Fn(i32) -> i32`,
496 we have a `[closure@<anon>:7:9: 7:20]`. Wait, what?
497
498 Because each closure generates its own environment `struct` and implementation
499 of `Fn` and friends, these types are anonymous. They exist solely for
500 this closure. So Rust shows them as `closure@<anon>`, rather than some
501 autogenerated name.
502
503 The error also points out that the return type is expected to be a reference,
504 but what we are trying to return is not. Further, we cannot directly assign a
505 `'static` lifetime to an object. So we'll take a different approach and return
506 a ‘trait object’ by `Box`ing up the `Fn`. This _almost_ works:
507
508 ```rust,ignore
509 fn factory() -> Box<Fn(i32) -> i32> {
510 let num = 5;
511
512 Box::new(|x| x + num)
513 }
514
515 let f = factory();
516
517 let answer = f(1);
518 assert_eq!(6, answer);
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
544 let f = factory();
545
546 let answer = f(1);
547 assert_eq!(6, answer);
548 ```
549
550 By making the inner closure a `move Fn`, we create a new stack frame for our
551 closure. By `Box`ing it up, we’ve given it a known size, allowing it to
552 escape our stack frame.