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