]> git.proxmox.com Git - rustc.git/blame - src/doc/book/closures.md
New upstream version 1.13.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
5bcae85e 226# #![feature(unboxed_closures)]
c34b1796
AL
227# mod foo {
228pub trait Fn<Args> : FnMut<Args> {
229 extern "rust-call" fn call(&self, args: Args) -> Self::Output;
1a4d82fc
JJ
230}
231
c34b1796
AL
232pub trait FnMut<Args> : FnOnce<Args> {
233 extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output;
234}
235
236pub trait FnOnce<Args> {
237 type Output;
1a4d82fc 238
c34b1796 239 extern "rust-call" fn call_once(self, args: Args) -> Self::Output;
1a4d82fc 240}
c34b1796 241# }
1a4d82fc
JJ
242```
243
bd371182 244You’ll notice a few differences between these traits, but a big one is `self`:
c34b1796 245`Fn` takes `&self`, `FnMut` takes `&mut self`, and `FnOnce` takes `self`. This
bd371182 246covers all three kinds of `self` via the usual method call syntax. But we’ve
c34b1796
AL
247split them up into three traits, rather than having a single one. This gives us
248a large amount of control over what kind of closures we can take.
1a4d82fc 249
c34b1796
AL
250The `|| {}` syntax for closures is sugar for these three traits. Rust will
251generate a struct for the environment, `impl` the appropriate trait, and then
252use it.
253
254# Taking closures as arguments
255
256Now that we know that closures are traits, we already know how to accept and
9cc50fc6 257return closures: the same as any other trait!
c34b1796
AL
258
259This also means that we can choose static vs dynamic dispatch as well. First,
bd371182 260let’s write a function which takes something callable, calls it, and returns
c34b1796
AL
261the result:
262
263```rust
264fn call_with_one<F>(some_closure: F) -> i32
9e0c209e 265 where F: Fn(i32) -> i32 {
c34b1796
AL
266
267 some_closure(1)
268}
1a4d82fc 269
c34b1796 270let answer = call_with_one(|x| x + 2);
1a4d82fc 271
c34b1796 272assert_eq!(3, answer);
1a4d82fc
JJ
273```
274
9cc50fc6 275We pass our closure, `|x| x + 2`, to `call_with_one`. It does what it
c34b1796 276suggests: it calls the closure, giving it `1` as an argument.
1a4d82fc 277
bd371182 278Let’s examine the signature of `call_with_one` in more depth:
1a4d82fc 279
c34b1796
AL
280```rust
281fn call_with_one<F>(some_closure: F) -> i32
9e0c209e 282# where F: Fn(i32) -> i32 {
c34b1796 283# some_closure(1) }
1a4d82fc
JJ
284```
285
c34b1796 286We take one parameter, and it has the type `F`. We also return a `i32`. This part
bd371182 287isn’t interesting. The next part is:
1a4d82fc 288
c34b1796
AL
289```rust
290# fn call_with_one<F>(some_closure: F) -> i32
9e0c209e 291 where F: Fn(i32) -> i32 {
c34b1796
AL
292# some_closure(1) }
293```
294
5bcae85e
SL
295Because `Fn` is a trait, we can use it as a bound for our generic type. In
296this case, our closure takes a `i32` as an argument and returns an `i32`, and
297so the generic bound we use is `Fn(i32) -> i32`.
1a4d82fc 298
bd371182
AL
299There’s one other key point here: because we’re bounding a generic with a
300trait, this will get monomorphized, and therefore, we’ll be doing static
301dispatch into the closure. That’s pretty neat. In many languages, closures are
c34b1796
AL
302inherently heap allocated, and will always involve dynamic dispatch. In Rust,
303we can stack allocate our closure environment, and statically dispatch the
304call. This happens quite often with iterators and their adapters, which often
305take closures as arguments.
1a4d82fc 306
c34b1796
AL
307Of course, if we want dynamic dispatch, we can get that too. A trait object
308handles this case, as usual:
1a4d82fc 309
c34b1796
AL
310```rust
311fn call_with_one(some_closure: &Fn(i32) -> i32) -> i32 {
312 some_closure(1)
1a4d82fc 313}
c34b1796
AL
314
315let answer = call_with_one(&|x| x + 2);
316
317assert_eq!(3, answer);
1a4d82fc
JJ
318```
319
c34b1796
AL
320Now we take a trait object, a `&Fn`. And we have to make a reference
321to our closure when we pass it to `call_with_one`, so we use `&||`.
1a4d82fc 322
a7813a04
XL
323A quick note about closures that use explicit lifetimes. Sometimes you might have a closure
324that takes a reference like so:
325
3157f602 326```rust
a7813a04
XL
327fn 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
335Normally you can specify the lifetime of the parameter to our closure. We
336could annotate it on the function declaration:
337
3157f602
XL
338```rust,ignore
339fn call_with_ref<'a, F>(some_closure:F) -> i32
5bcae85e 340 where F: Fn(&'a i32) -> i32 {
a7813a04
XL
341```
342
9e0c209e 343However this presents a problem in our case. When you specify the explicit
a7813a04
XL
344lifetime on a function it binds that lifetime to the *entire* scope of the function
345instead of just the invocation scope of our closure. This means that the borrow checker
346will see a mutable reference in the same lifetime as our immutable reference and fail
347to compile.
348
349In order to say that we only need the lifetime to be valid for the invocation scope
350of the closure we can use Higher-Ranked Trait Bounds with the `for<...>` syntax:
351
352```ignore
353fn call_with_ref<F>(some_closure:F) -> i32
5bcae85e 354 where F: for<'a> Fn(&'a i32) -> i32 {
a7813a04
XL
355```
356
3157f602 357This lets the Rust compiler find the minimum lifetime to invoke our closure and
5bcae85e 358satisfy the borrow checker's rules. Our function then compiles and executes as we
a7813a04
XL
359expect.
360
3157f602 361```rust
a7813a04
XL
362fn 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
e9174d1e
SL
370# Function pointers and closures
371
372A function pointer is kind of like a closure that has no environment. As such,
373you can pass a function pointer to any function expecting a closure argument,
374and it will work:
375
376```rust
377fn call_with_one(some_closure: &Fn(i32) -> i32) -> i32 {
378 some_closure(1)
379}
380
381fn add_one(i: i32) -> i32 {
382 i + 1
383}
384
385let f = add_one;
386
387let answer = call_with_one(&f);
388
389assert_eq!(2, answer);
390```
391
392In this example, we don’t strictly need the intermediate variable `f`,
393the name of the function works just fine too:
394
a7813a04 395```rust,ignore
e9174d1e
SL
396let answer = call_with_one(&add_one);
397```
398
c34b1796 399# Returning closures
1a4d82fc 400
c34b1796
AL
401It’s very common for functional-style code to return closures in various
402situations. If you try to return a closure, you may run into an error. At
bd371182 403first, it may seem strange, but we’ll figure it out. Here’s how you’d probably
c34b1796 404try to return a closure from a function:
1a4d82fc 405
c34b1796 406```rust,ignore
62682a34
SL
407fn factory() -> (Fn(i32) -> i32) {
408 let num = 5;
1a4d82fc 409
62682a34 410 |x| x + num
1a4d82fc
JJ
411}
412
c34b1796
AL
413let f = factory();
414
62682a34
SL
415let answer = f(1);
416assert_eq!(6, answer);
1a4d82fc
JJ
417```
418
c34b1796
AL
419This gives us these long, related errors:
420
421```text
54a0048b 422error: the trait bound `core::ops::Fn(i32) -> i32 : core::marker::Sized` is not satisfied [E0277]
62682a34
SL
423fn factory() -> (Fn(i32) -> i32) {
424 ^~~~~~~~~~~~~~~~
425note: `core::ops::Fn(i32) -> i32` does not have a constant size known at compile-time
426fn factory() -> (Fn(i32) -> i32) {
427 ^~~~~~~~~~~~~~~~
54a0048b 428error: the trait bound `core::ops::Fn(i32) -> i32 : core::marker::Sized` is not satisfied [E0277]
62682a34
SL
429let f = factory();
430 ^
431note: `core::ops::Fn(i32) -> i32` does not have a constant size known at compile-time
432let f = factory();
433 ^
c34b1796 434```
1a4d82fc 435
c34b1796
AL
436In order to return something from a function, Rust needs to know what
437size the return type is. But since `Fn` is a trait, it could be various
438things of various sizes: many different types can implement `Fn`. An easy
439way to give something a size is to take a reference to it, as references
bd371182 440have a known size. So we’d write this:
1a4d82fc 441
c34b1796 442```rust,ignore
62682a34
SL
443fn factory() -> &(Fn(i32) -> i32) {
444 let num = 5;
c34b1796 445
62682a34 446 |x| x + num
1a4d82fc 447}
c34b1796
AL
448
449let f = factory();
450
62682a34
SL
451let answer = f(1);
452assert_eq!(6, answer);
c34b1796
AL
453```
454
455But we get another error:
456
457```text
458error: missing lifetime specifier [E0106]
459fn factory() -> &(Fn(i32) -> i32) {
460 ^~~~~~~~~~~~~~~~~
1a4d82fc
JJ
461```
462
c34b1796 463Right. Because we have a reference, we need to give it a lifetime. But
b039eaaf
SL
464our `factory()` function takes no arguments, so
465[elision](lifetimes.html#lifetime-elision) doesn’t kick in here. Then what
466choices do we have? Try `'static`:
1a4d82fc 467
c34b1796
AL
468```rust,ignore
469fn factory() -> &'static (Fn(i32) -> i32) {
470 let num = 5;
85aaf69f 471
c34b1796 472 |x| x + num
85aaf69f
SL
473}
474
c34b1796
AL
475let f = factory();
476
477let answer = f(1);
478assert_eq!(6, answer);
479```
480
481But we get another error:
482
483```text
484error: mismatched types:
485 expected `&'static core::ops::Fn(i32) -> i32`,
b039eaaf 486 found `[closure@<anon>:7:9: 7:20]`
c34b1796
AL
487(expected &-ptr,
488 found closure) [E0308]
489 |x| x + num
490 ^~~~~~~~~~~
491
492```
493
bd371182 494This error is letting us know that we don’t have a `&'static Fn(i32) -> i32`,
b039eaaf 495we have a `[closure@<anon>:7:9: 7:20]`. Wait, what?
c34b1796
AL
496
497Because each closure generates its own environment `struct` and implementation
9cc50fc6 498of `Fn` and friends, these types are anonymous. They exist solely for
b039eaaf 499this closure. So Rust shows them as `closure@<anon>`, rather than some
c34b1796
AL
500autogenerated name.
501
b039eaaf
SL
502The error also points out that the return type is expected to be a reference,
503but 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
505a ‘trait object’ by `Box`ing up the `Fn`. This _almost_ works:
c34b1796
AL
506
507```rust,ignore
508fn factory() -> Box<Fn(i32) -> i32> {
509 let num = 5;
510
511 Box::new(|x| x + num)
85aaf69f 512}
c34b1796
AL
513# fn main() {
514let f = factory();
515
516let answer = f(1);
517assert_eq!(6, answer);
518# }
85aaf69f
SL
519```
520
b039eaaf 521There’s just one last problem:
85aaf69f 522
c34b1796 523```text
62682a34
SL
524error: closure may outlive the current function, but it borrows `num`,
525which is owned by the current function [E0373]
c34b1796
AL
526Box::new(|x| x + num)
527 ^~~~~~~~~~~
528```
529
b039eaaf
SL
530Well, as we discussed before, closures borrow their environment. And in this
531case, our environment is based on a stack-allocated `5`, the `num` variable
532binding. So the borrow has a lifetime of the stack frame. So if we returned
533this closure, the function call would be over, the stack frame would go away,
534and our closure is capturing an environment of garbage memory! With one last
535fix, we can make this work:
85aaf69f 536
c34b1796
AL
537```rust
538fn factory() -> Box<Fn(i32) -> i32> {
539 let num = 5;
85aaf69f 540
c34b1796
AL
541 Box::new(move |x| x + num)
542}
a7813a04 543fn main() {
c34b1796
AL
544let f = factory();
545
546let answer = f(1);
547assert_eq!(6, answer);
a7813a04 548}
c34b1796 549```
85aaf69f 550
c34b1796 551By making the inner closure a `move Fn`, we create a new stack frame for our
54a0048b 552closure. By `Box`ing it up, we’ve given it a known size, allowing it to
c34b1796 553escape our stack frame.