]> git.proxmox.com Git - rustc.git/blob - src/doc/book/src/ch13-01-closures.md
New upstream version 1.52.0~beta.3+dfsg1
[rustc.git] / src / doc / book / src / ch13-01-closures.md
1 ## Closures: Anonymous Functions that Can Capture Their Environment
2
3 Rust’s closures are anonymous functions you can save in a variable or pass as
4 arguments to other functions. You can create the closure in one place and then
5 call the closure to evaluate it in a different context. Unlike functions,
6 closures can capture values from the scope in which they’re defined. We’ll
7 demonstrate how these closure features allow for code reuse and behavior
8 customization.
9
10 ### Creating an Abstraction of Behavior with Closures
11
12 Let’s work on an example of a situation in which it’s useful to store a closure
13 to be executed later. Along the way, we’ll talk about the syntax of closures,
14 type inference, and traits.
15
16 Consider this hypothetical situation: we work at a startup that’s making an app
17 to generate custom exercise workout plans. The backend is written in Rust, and
18 the algorithm that generates the workout plan takes into account many factors,
19 such as the app user’s age, body mass index, exercise preferences, recent
20 workouts, and an intensity number they specify. The actual algorithm used isn’t
21 important in this example; what’s important is that this calculation takes a
22 few seconds. We want to call this algorithm only when we need to and only call
23 it once so we don’t make the user wait more than necessary.
24
25 We’ll simulate calling this hypothetical algorithm with the function
26 `simulated_expensive_calculation` shown in Listing 13-1, which will print
27 `calculating slowly...`, wait for two seconds, and then return whatever number
28 we passed in.
29
30 <span class="filename">Filename: src/main.rs</span>
31
32 ```rust
33 {{#rustdoc_include ../listings/ch13-functional-features/listing-13-01/src/main.rs:here}}
34 ```
35
36 <span class="caption">Listing 13-1: A function to stand in for a hypothetical
37 calculation that takes about 2 seconds to run</span>
38
39 Next is the `main` function, which contains the parts of the workout app
40 important for this example. This function represents the code that the app will
41 call when a user asks for a workout plan. Because the interaction with the
42 app’s frontend isn’t relevant to the use of closures, we’ll hardcode values
43 representing inputs to our program and print the outputs.
44
45 The required inputs are these:
46
47 * An intensity number from the user, which is specified when they request
48 a workout to indicate whether they want a low-intensity workout or a
49 high-intensity workout
50 * A random number that will generate some variety in the workout plans
51
52 The output will be the recommended workout plan. Listing 13-2 shows the `main`
53 function we’ll use.
54
55 <span class="filename">Filename: src/main.rs</span>
56
57 ```rust
58 {{#rustdoc_include ../listings/ch13-functional-features/listing-13-02/src/main.rs:here}}
59 ```
60
61 <span class="caption">Listing 13-2: A `main` function with hardcoded values to
62 simulate user input and random number generation</span>
63
64 We’ve hardcoded the variable `simulated_user_specified_value` as 10 and the
65 variable `simulated_random_number` as 7 for simplicity’s sake; in an actual
66 program, we’d get the intensity number from the app frontend, and we’d use the
67 `rand` crate to generate a random number, as we did in the Guessing Game
68 example in Chapter 2. The `main` function calls a `generate_workout` function
69 with the simulated input values.
70
71 Now that we have the context, let’s get to the algorithm. The function
72 `generate_workout` in Listing 13-3 contains the business logic of the
73 app that we’re most concerned with in this example. The rest of the code
74 changes in this example will be made to this function.
75
76 <span class="filename">Filename: src/main.rs</span>
77
78 ```rust
79 {{#rustdoc_include ../listings/ch13-functional-features/listing-13-03/src/main.rs:here}}
80 ```
81
82 <span class="caption">Listing 13-3: The business logic that prints the workout
83 plans based on the inputs and calls to the `simulated_expensive_calculation`
84 function</span>
85
86 The code in Listing 13-3 has multiple calls to the slow calculation function.
87 The first `if` block calls `simulated_expensive_calculation` twice, the `if`
88 inside the outer `else` doesn’t call it at all, and the code inside the
89 second `else` case calls it once.
90
91 The desired behavior of the `generate_workout` function is to first check
92 whether the user wants a low-intensity workout (indicated by a number less than
93 25) or a high-intensity workout (a number of 25 or greater).
94
95 Low-intensity workout plans will recommend a number of push-ups and sit-ups
96 based on the complex algorithm we’re simulating.
97
98 If the user wants a high-intensity workout, there’s some additional logic: if
99 the value of the random number generated by the app happens to be 3, the app
100 will recommend a break and hydration. If not, the user will get a number of
101 minutes of running based on the complex algorithm.
102
103 This code works the way the business wants it to now, but let’s say the data
104 science team decides that we need to make some changes to the way we call the
105 `simulated_expensive_calculation` function in the future. To simplify the
106 update when those changes happen, we want to refactor this code so it calls the
107 `simulated_expensive_calculation` function only once. We also want to cut the
108 place where we’re currently unnecessarily calling the function twice without
109 adding any other calls to that function in the process. That is, we don’t want
110 to call it if the result isn’t needed, and we still want to call it only once.
111
112 #### Refactoring Using Functions
113
114 We could restructure the workout program in many ways. First, we’ll try
115 extracting the duplicated call to the `simulated_expensive_calculation`
116 function into a variable, as shown in Listing 13-4.
117
118 <span class="filename">Filename: src/main.rs</span>
119
120 ```rust
121 {{#rustdoc_include ../listings/ch13-functional-features/listing-13-04/src/main.rs:here}}
122 ```
123
124 <span class="caption">Listing 13-4: Extracting the calls to
125 `simulated_expensive_calculation` to one place and storing the result in the
126 `expensive_result` variable</span>
127
128 This change unifies all the calls to `simulated_expensive_calculation` and
129 solves the problem of the first `if` block unnecessarily calling the function
130 twice. Unfortunately, we’re now calling this function and waiting for the
131 result in all cases, which includes the inner `if` block that doesn’t use the
132 result value at all.
133
134 We want to refer to `simulated_expensive_calculation` only once in
135 `generate_workout`, but defer the expensive calculation to only where
136 we actually need the result. This is a use case for closures!
137
138 #### Refactoring with Closures to Store Code
139
140 Instead of always calling the `simulated_expensive_calculation` function before
141 the `if` blocks, we can define a closure and store the *closure* in a variable
142 rather than storing the result of the function call, as shown in Listing 13-5.
143 We can actually move the whole body of `simulated_expensive_calculation` within
144 the closure we’re introducing here.
145
146 <span class="filename">Filename: src/main.rs</span>
147
148 ```rust
149 {{#rustdoc_include ../listings/ch13-functional-features/listing-13-05/src/main.rs:here}}
150 ```
151
152 <span class="caption">Listing 13-5: Defining a closure and storing it in the
153 `expensive_closure` variable</span>
154
155 The closure definition comes after the `=` to assign it to the variable
156 `expensive_closure`. To define a closure, we start with a pair of vertical
157 pipes (`|`), inside which we specify the parameters to the closure; this syntax
158 was chosen because of its similarity to closure definitions in Smalltalk and
159 Ruby. This closure has one parameter named `num`: if we had more than one
160 parameter, we would separate them with commas, like `|param1, param2|`.
161
162 After the parameters, we place curly brackets that hold the body of the
163 closure—these are optional if the closure body is a single expression. The end
164 of the closure, after the curly brackets, needs a semicolon to complete the
165 `let` statement. The value returned from the last line in the closure body
166 (`num`) will be the value returned from the closure when it’s called, because
167 that line doesn’t end in a semicolon; just as in function bodies.
168
169 Note that this `let` statement means `expensive_closure` contains the
170 *definition* of an anonymous function, not the *resulting value* of calling the
171 anonymous function. Recall that we’re using a closure because we want to define
172 the code to call at one point, store that code, and call it at a later point;
173 the code we want to call is now stored in `expensive_closure`.
174
175 With the closure defined, we can change the code in the `if` blocks to call the
176 closure to execute the code and get the resulting value. We call a closure like
177 we do a function: we specify the variable name that holds the closure
178 definition and follow it with parentheses containing the argument values we
179 want to use, as shown in Listing 13-6.
180
181 <span class="filename">Filename: src/main.rs</span>
182
183 ```rust
184 {{#rustdoc_include ../listings/ch13-functional-features/listing-13-06/src/main.rs:here}}
185 ```
186
187 <span class="caption">Listing 13-6: Calling the `expensive_closure` we’ve
188 defined</span>
189
190 Now how to perform the expensive calculation is defined in only one
191 place, and we’re only executing that code where we need the results.
192
193 However, we’ve reintroduced one of the problems from Listing 13-3: we’re still
194 calling the closure twice in the first `if` block, which will call the
195 expensive code twice and make the user wait twice as long as they need to. We
196 could fix this problem by creating a variable local to that `if` block to hold
197 the result of calling the closure, but closures provide us with another
198 solution. We’ll talk about that solution in a bit. But first let’s talk about
199 why there aren’t type annotations in the closure definition and the traits
200 involved with closures.
201
202 ### Closure Type Inference and Annotation
203
204 Closures don’t require you to annotate the types of the parameters or the
205 return value like `fn` functions do. Type annotations are required on functions
206 because they’re part of an explicit interface exposed to your users. Defining
207 this interface rigidly is important for ensuring that everyone agrees on what
208 types of values a function uses and returns. But closures aren’t used in an
209 exposed interface like this: they’re stored in variables and used without
210 naming them and exposing them to users of our library.
211
212 Closures are usually short and relevant only within a narrow context rather
213 than in any arbitrary scenario. Within these limited contexts, the compiler is
214 reliably able to infer the types of the parameters and the return type, similar
215 to how it’s able to infer the types of most variables.
216
217 Making programmers annotate the types in these small, anonymous functions would
218 be annoying and largely redundant with the information the compiler already has
219 available.
220
221 As with variables, we can add type annotations if we want to increase
222 explicitness and clarity at the cost of being more verbose than is strictly
223 necessary. Annotating the types for the closure we defined in Listing 13-5
224 would look like the definition shown in Listing 13-7.
225
226 <span class="filename">Filename: src/main.rs</span>
227
228 ```rust
229 {{#rustdoc_include ../listings/ch13-functional-features/listing-13-07/src/main.rs:here}}
230 ```
231
232 <span class="caption">Listing 13-7: Adding optional type annotations of the
233 parameter and return value types in the closure</span>
234
235 With type annotations added, the syntax of closures looks more similar to the
236 syntax of functions. The following is a vertical comparison of the syntax for
237 the definition of a function that adds 1 to its parameter and a closure that
238 has the same behavior. We’ve added some spaces to line up the relevant parts.
239 This illustrates how closure syntax is similar to function syntax except for
240 the use of pipes and the amount of syntax that is optional:
241
242 ```rust,ignore
243 fn add_one_v1 (x: u32) -> u32 { x + 1 }
244 let add_one_v2 = |x: u32| -> u32 { x + 1 };
245 let add_one_v3 = |x| { x + 1 };
246 let add_one_v4 = |x| x + 1 ;
247 ```
248
249 The first line shows a function definition, and the second line shows a fully
250 annotated closure definition. The third line removes the type annotations from
251 the closure definition, and the fourth line removes the brackets, which are
252 optional because the closure body has only one expression. These are all valid
253 definitions that will produce the same behavior when they’re called. Calling
254 the closures is required for `add_one_v3` and `add_one_v4` to be able to
255 compile because the types will be inferred from their usage.
256
257 Closure definitions will have one concrete type inferred for each of their
258 parameters and for their return value. For instance, Listing 13-8 shows the
259 definition of a short closure that just returns the value it receives as a
260 parameter. This closure isn’t very useful except for the purposes of this
261 example. Note that we haven’t added any type annotations to the definition: if
262 we then try to call the closure twice, using a `String` as an argument the
263 first time and a `u32` the second time, we’ll get an error.
264
265 <span class="filename">Filename: src/main.rs</span>
266
267 ```rust,ignore,does_not_compile
268 {{#rustdoc_include ../listings/ch13-functional-features/listing-13-08/src/main.rs:here}}
269 ```
270
271 <span class="caption">Listing 13-8: Attempting to call a closure whose types
272 are inferred with two different types</span>
273
274 The compiler gives us this error:
275
276 ```console
277 {{#include ../listings/ch13-functional-features/listing-13-08/output.txt}}
278 ```
279
280 The first time we call `example_closure` with the `String` value, the compiler
281 infers the type of `x` and the return type of the closure to be `String`. Those
282 types are then locked into the closure in `example_closure`, and we get a type
283 error if we try to use a different type with the same closure.
284
285 ### Storing Closures Using Generic Parameters and the `Fn` Traits
286
287 Let’s return to our workout generation app. In Listing 13-6, our code was still
288 calling the expensive calculation closure more times than it needed to. One
289 option to solve this issue is to save the result of the expensive closure in a
290 variable for reuse and use the variable in each place we need the result,
291 instead of calling the closure again. However, this method could result in a
292 lot of repeated code.
293
294 Fortunately, another solution is available to us. We can create a struct that
295 will hold the closure and the resulting value of calling the closure. The
296 struct will execute the closure only if we need the resulting value, and it
297 will cache the resulting value so the rest of our code doesn’t have to be
298 responsible for saving and reusing the result. You may know this pattern as
299 *memoization* or *lazy evaluation*.
300
301 To make a struct that holds a closure, we need to specify the type of the
302 closure, because a struct definition needs to know the types of each of its
303 fields. Each closure instance has its own unique anonymous type: that is, even
304 if two closures have the same signature, their types are still considered
305 different. To define structs, enums, or function parameters that use closures,
306 we use generics and trait bounds, as we discussed in Chapter 10.
307
308 The `Fn` traits are provided by the standard library. All closures implement at
309 least one of the traits: `Fn`, `FnMut`, or `FnOnce`. We’ll discuss the
310 difference between these traits in the [“Capturing the Environment with
311 Closures”](#capturing-the-environment-with-closures)<!-- ignore --> section; in
312 this example, we can use the `Fn` trait.
313
314 We add types to the `Fn` trait bound to represent the types of the parameters
315 and return values the closures must have to match this trait bound. In this
316 case, our closure has a parameter of type `u32` and returns a `u32`, so the
317 trait bound we specify is `Fn(u32) -> u32`.
318
319 Listing 13-9 shows the definition of the `Cacher` struct that holds a closure
320 and an optional result value.
321
322 <span class="filename">Filename: src/main.rs</span>
323
324 ```rust
325 {{#rustdoc_include ../listings/ch13-functional-features/listing-13-09/src/main.rs:here}}
326 ```
327
328 <span class="caption">Listing 13-9: Defining a `Cacher` struct that holds a
329 closure in `calculation` and an optional result in `value`</span>
330
331 The `Cacher` struct has a `calculation` field of the generic type `T`. The
332 trait bounds on `T` specify that it’s a closure by using the `Fn` trait. Any
333 closure we want to store in the `calculation` field must have one `u32`
334 parameter (specified within the parentheses after `Fn`) and must return a
335 `u32` (specified after the `->`).
336
337 > Note: Functions can implement all three of the `Fn` traits too. If what we
338 > want to do doesn’t require capturing a value from the environment, we can use
339 > a function rather than a closure where we need something that implements an
340 > `Fn` trait.
341
342 The `value` field is of type `Option<u32>`. Before we execute the closure,
343 `value` will be `None`. When code using a `Cacher` asks for the *result* of the
344 closure, the `Cacher` will execute the closure at that time and store the
345 result within a `Some` variant in the `value` field. Then if the code asks for
346 the result of the closure again, instead of executing the closure again, the
347 `Cacher` will return the result held in the `Some` variant.
348
349 The logic around the `value` field we’ve just described is defined in Listing
350 13-10.
351
352 <span class="filename">Filename: src/main.rs</span>
353
354 ```rust
355 {{#rustdoc_include ../listings/ch13-functional-features/listing-13-10/src/main.rs:here}}
356 ```
357
358 <span class="caption">Listing 13-10: The caching logic of `Cacher`</span>
359
360 We want `Cacher` to manage the struct fields’ values rather than letting the
361 calling code potentially change the values in these fields directly, so these
362 fields are private.
363
364 The `Cacher::new` function takes a generic parameter `T`, which we’ve defined
365 as having the same trait bound as the `Cacher` struct. Then `Cacher::new`
366 returns a `Cacher` instance that holds the closure specified in the
367 `calculation` field and a `None` value in the `value` field, because we haven’t
368 executed the closure yet.
369
370 When the calling code needs the result of evaluating the closure, instead of
371 calling the closure directly, it will call the `value` method. This method
372 checks whether we already have a resulting value in `self.value` in a `Some`;
373 if we do, it returns the value within the `Some` without executing the closure
374 again.
375
376 If `self.value` is `None`, the code calls the closure stored in
377 `self.calculation`, saves the result in `self.value` for future use, and
378 returns the value as well.
379
380 Listing 13-11 shows how we can use this `Cacher` struct in the function
381 `generate_workout` from Listing 13-6.
382
383 <span class="filename">Filename: src/main.rs</span>
384
385 ```rust
386 {{#rustdoc_include ../listings/ch13-functional-features/listing-13-11/src/main.rs:here}}
387 ```
388
389 <span class="caption">Listing 13-11: Using `Cacher` in the `generate_workout`
390 function to abstract away the caching logic</span>
391
392 Instead of saving the closure in a variable directly, we save a new instance of
393 `Cacher` that holds the closure. Then, in each place we want the result, we
394 call the `value` method on the `Cacher` instance. We can call the `value`
395 method as many times as we want, or not call it at all, and the expensive
396 calculation will be run a maximum of once.
397
398 Try running this program with the `main` function from Listing 13-2. Change the
399 values in the `simulated_user_specified_value` and `simulated_random_number`
400 variables to verify that in all the cases in the various `if` and `else`
401 blocks, `calculating slowly...` appears only once and only when needed. The
402 `Cacher` takes care of the logic necessary to ensure we aren’t calling the
403 expensive calculation more than we need to so `generate_workout` can focus on
404 the business logic.
405
406 ### Limitations of the `Cacher` Implementation
407
408 Caching values is a generally useful behavior that we might want to use in
409 other parts of our code with different closures. However, there are two
410 problems with the current implementation of `Cacher` that would make reusing it
411 in different contexts difficult.
412
413 The first problem is that a `Cacher` instance assumes it will always get the
414 same value for the parameter `arg` to the `value` method. That is, this test of
415 `Cacher` will fail:
416
417 ```rust,ignore,panics
418 {{#rustdoc_include ../listings/ch13-functional-features/no-listing-01-failing-cacher-test/src/lib.rs:here}}
419 ```
420
421 This test creates a new `Cacher` instance with a closure that returns the value
422 passed into it. We call the `value` method on this `Cacher` instance with an
423 `arg` value of 1 and then an `arg` value of 2, and we expect the call to
424 `value` with the `arg` value of 2 to return 2.
425
426 Run this test with the `Cacher` implementation in Listing 13-9 and Listing
427 13-10, and the test will fail on the `assert_eq!` with this message:
428
429 ```console
430 {{#include ../listings/ch13-functional-features/no-listing-01-failing-cacher-test/output.txt}}
431 ```
432
433 The problem is that the first time we called `c.value` with 1, the `Cacher`
434 instance saved `Some(1)` in `self.value`. Thereafter, no matter what we pass into
435 the `value` method, it will always return 1.
436
437 Try modifying `Cacher` to hold a hash map rather than a single value. The keys
438 of the hash map will be the `arg` values that are passed in, and the values of
439 the hash map will be the result of calling the closure on that key. Instead of
440 looking at whether `self.value` directly has a `Some` or a `None` value, the
441 `value` function will look up the `arg` in the hash map and return the value if
442 it’s present. If it’s not present, the `Cacher` will call the closure and save
443 the resulting value in the hash map associated with its `arg` value.
444
445 The second problem with the current `Cacher` implementation is that it only
446 accepts closures that take one parameter of type `u32` and return a `u32`. We
447 might want to cache the results of closures that take a string slice and return
448 `usize` values, for example. To fix this issue, try introducing more generic
449 parameters to increase the flexibility of the `Cacher` functionality.
450
451 ### Capturing the Environment with Closures
452
453 In the workout generator example, we only used closures as inline anonymous
454 functions. However, closures have an additional capability that functions don’t
455 have: they can capture their environment and access variables from the scope in
456 which they’re defined.
457
458 Listing 13-12 has an example of a closure stored in the `equal_to_x` variable
459 that uses the `x` variable from the closure’s surrounding environment.
460
461 <span class="filename">Filename: src/main.rs</span>
462
463 ```rust
464 {{#rustdoc_include ../listings/ch13-functional-features/listing-13-12/src/main.rs}}
465 ```
466
467 <span class="caption">Listing 13-12: Example of a closure that refers to a
468 variable in its enclosing scope</span>
469
470 Here, even though `x` is not one of the parameters of `equal_to_x`, the
471 `equal_to_x` closure is allowed to use the `x` variable that’s defined in the
472 same scope that `equal_to_x` is defined in.
473
474 We can’t do the same with functions; if we try with the following example, our
475 code won’t compile:
476
477 <span class="filename">Filename: src/main.rs</span>
478
479 ```rust,ignore,does_not_compile
480 {{#rustdoc_include ../listings/ch13-functional-features/no-listing-02-functions-cant-capture/src/main.rs}}
481 ```
482
483 We get an error:
484
485 ```console
486 {{#include ../listings/ch13-functional-features/no-listing-02-functions-cant-capture/output.txt}}
487 ```
488
489 The compiler even reminds us that this only works with closures!
490
491 When a closure captures a value from its environment, it uses memory to store
492 the values for use in the closure body. This use of memory is overhead that we
493 don’t want to pay in more common cases where we want to execute code that
494 doesn’t capture its environment. Because functions are never allowed to capture
495 their environment, defining and using functions will never incur this overhead.
496
497 Closures can capture values from their environment in three ways, which
498 directly map to the three ways a function can take a parameter: taking
499 ownership, borrowing mutably, and borrowing immutably. These are encoded in the
500 three `Fn` traits as follows:
501
502 * `FnOnce` consumes the variables it captures from its enclosing scope, known
503 as the closure’s *environment*. To consume the captured variables, the
504 closure must take ownership of these variables and move them into the closure
505 when it is defined. The `Once` part of the name represents the fact that the
506 closure can’t take ownership of the same variables more than once, so it can
507 be called only once.
508 * `FnMut` can change the environment because it mutably borrows values.
509 * `Fn` borrows values from the environment immutably.
510
511 When you create a closure, Rust infers which trait to use based on how the
512 closure uses the values from the environment. All closures implement `FnOnce`
513 because they can all be called at least once. Closures that don’t move the
514 captured variables also implement `FnMut`, and closures that don’t need mutable
515 access to the captured variables also implement `Fn`. In Listing 13-12, the
516 `equal_to_x` closure borrows `x` immutably (so `equal_to_x` has the `Fn` trait)
517 because the body of the closure only needs to read the value in `x`.
518
519 If you want to force the closure to take ownership of the values it uses in the
520 environment, you can use the `move` keyword before the parameter list. This
521 technique is mostly useful when passing a closure to a new thread to move the
522 data so it’s owned by the new thread.
523
524 > Note: `move` closures may still implement `Fn` or `FnMut`, even though
525 > they capture variables by move. This is because the traits implemented by a
526 > closure type are determined by what the closure does with captured values,
527 > not how it captures them. The `move` keyword only specifies the latter.
528
529 We’ll have more examples of `move` closures in Chapter 16 when we talk about
530 concurrency. For now, here’s the code from Listing 13-12 with the `move`
531 keyword added to the closure definition and using vectors instead of integers,
532 because integers can be copied rather than moved; note that this code will not
533 yet compile.
534
535 <span class="filename">Filename: src/main.rs</span>
536
537 ```rust,ignore,does_not_compile
538 {{#rustdoc_include ../listings/ch13-functional-features/no-listing-03-move-closures/src/main.rs}}
539 ```
540
541 We receive the following error:
542
543 ```console
544 {{#include ../listings/ch13-functional-features/no-listing-03-move-closures/output.txt}}
545 ```
546
547 The `x` value is moved into the closure when the closure is defined, because we
548 added the `move` keyword. The closure then has ownership of `x`, and `main`
549 isn’t allowed to use `x` anymore in the `println!` statement. Removing
550 `println!` will fix this example.
551
552 Most of the time when specifying one of the `Fn` trait bounds, you can start
553 with `Fn` and the compiler will tell you if you need `FnMut` or `FnOnce` based
554 on what happens in the closure body.
555
556 To illustrate situations where closures that can capture their environment are
557 useful as function parameters, let’s move on to our next topic: iterators.