]>
Commit | Line | Data |
---|---|---|
13cf67c4 XL |
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 | |
9fa01778 | 28 | we passed in. |
13cf67c4 XL |
29 | |
30 | <span class="filename">Filename: src/main.rs</span> | |
31 | ||
32 | ```rust | |
74b04a01 | 33 | {{#rustdoc_include ../listings/ch13-functional-features/listing-13-01/src/main.rs:here}} |
13cf67c4 XL |
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` | |
9fa01778 | 53 | function we’ll use. |
13cf67c4 XL |
54 | |
55 | <span class="filename">Filename: src/main.rs</span> | |
56 | ||
57 | ```rust | |
74b04a01 | 58 | {{#rustdoc_include ../listings/ch13-functional-features/listing-13-02/src/main.rs:here}} |
13cf67c4 XL |
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 | |
74b04a01 | 79 | {{#rustdoc_include ../listings/ch13-functional-features/listing-13-03/src/main.rs:here}} |
13cf67c4 XL |
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 | ||
13cf67c4 | 91 | The desired behavior of the `generate_workout` function is to first check |
e74abb32 XL |
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). | |
13cf67c4 XL |
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` | |
9fa01778 | 116 | function into a variable, as shown in Listing 13-4. |
13cf67c4 XL |
117 | |
118 | <span class="filename">Filename: src/main.rs</span> | |
119 | ||
120 | ```rust | |
74b04a01 | 121 | {{#rustdoc_include ../listings/ch13-functional-features/listing-13-04/src/main.rs:here}} |
13cf67c4 XL |
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 | ||
6a06907d XL |
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! | |
13cf67c4 XL |
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 | |
9fa01778 | 144 | the closure we’re introducing here. |
13cf67c4 XL |
145 | |
146 | <span class="filename">Filename: src/main.rs</span> | |
147 | ||
148 | ```rust | |
74b04a01 | 149 | {{#rustdoc_include ../listings/ch13-functional-features/listing-13-05/src/main.rs:here}} |
13cf67c4 XL |
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 | |
9fa01778 | 167 | that line doesn’t end in a semicolon; just as in function bodies. |
13cf67c4 XL |
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 | |
9fa01778 | 179 | want to use, as shown in Listing 13-6. |
13cf67c4 XL |
180 | |
181 | <span class="filename">Filename: src/main.rs</span> | |
182 | ||
183 | ```rust | |
74b04a01 | 184 | {{#rustdoc_include ../listings/ch13-functional-features/listing-13-06/src/main.rs:here}} |
13cf67c4 XL |
185 | ``` |
186 | ||
187 | <span class="caption">Listing 13-6: Calling the `expensive_closure` we’ve | |
188 | defined</span> | |
189 | ||
6a06907d XL |
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. | |
13cf67c4 XL |
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 | |
9fa01778 | 224 | would look like the definition shown in Listing 13-7. |
13cf67c4 XL |
225 | |
226 | <span class="filename">Filename: src/main.rs</span> | |
227 | ||
228 | ```rust | |
74b04a01 | 229 | {{#rustdoc_include ../listings/ch13-functional-features/listing-13-07/src/main.rs:here}} |
13cf67c4 XL |
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 | |
74b04a01 XL |
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. | |
13cf67c4 XL |
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 | |
74b04a01 | 268 | {{#rustdoc_include ../listings/ch13-functional-features/listing-13-08/src/main.rs:here}} |
13cf67c4 XL |
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 | ||
f035d41b | 276 | ```console |
74b04a01 | 277 | {{#include ../listings/ch13-functional-features/listing-13-08/output.txt}} |
13cf67c4 XL |
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 | |
5869c6ff | 282 | types are then locked into the closure in `example_closure`, and we get a type |
13cf67c4 XL |
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 | |
9fa01778 XL |
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. | |
13cf67c4 XL |
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 | |
9fa01778 | 320 | and an optional result value. |
13cf67c4 XL |
321 | |
322 | <span class="filename">Filename: src/main.rs</span> | |
323 | ||
324 | ```rust | |
74b04a01 | 325 | {{#rustdoc_include ../listings/ch13-functional-features/listing-13-09/src/main.rs:here}} |
13cf67c4 XL |
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 | |
9fa01778 | 350 | 13-10. |
13cf67c4 XL |
351 | |
352 | <span class="filename">Filename: src/main.rs</span> | |
353 | ||
354 | ```rust | |
74b04a01 | 355 | {{#rustdoc_include ../listings/ch13-functional-features/listing-13-10/src/main.rs:here}} |
13cf67c4 XL |
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 | |
9fa01778 | 381 | `generate_workout` from Listing 13-6. |
13cf67c4 XL |
382 | |
383 | <span class="filename">Filename: src/main.rs</span> | |
384 | ||
385 | ```rust | |
74b04a01 | 386 | {{#rustdoc_include ../listings/ch13-functional-features/listing-13-11/src/main.rs:here}} |
13cf67c4 XL |
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 | |
74b04a01 | 418 | {{#rustdoc_include ../listings/ch13-functional-features/no-listing-01-failing-cacher-test/src/lib.rs:here}} |
13cf67c4 XL |
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 | |
9fa01778 | 424 | `value` with the `arg` value of 2 to return 2. |
13cf67c4 XL |
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 | ||
f035d41b | 429 | ```console |
74b04a01 | 430 | {{#include ../listings/ch13-functional-features/no-listing-01-failing-cacher-test/output.txt}} |
13cf67c4 XL |
431 | ``` |
432 | ||
433 | The problem is that the first time we called `c.value` with 1, the `Cacher` | |
5869c6ff XL |
434 | instance saved `Some(1)` in `self.value`. Thereafter, no matter what we pass into |
435 | the `value` method, it will always return 1. | |
13cf67c4 XL |
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 | |
9fa01778 | 459 | that uses the `x` variable from the closure’s surrounding environment. |
13cf67c4 XL |
460 | |
461 | <span class="filename">Filename: src/main.rs</span> | |
462 | ||
463 | ```rust | |
74b04a01 | 464 | {{#rustdoc_include ../listings/ch13-functional-features/listing-13-12/src/main.rs}} |
13cf67c4 XL |
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 | |
74b04a01 | 480 | {{#rustdoc_include ../listings/ch13-functional-features/no-listing-02-functions-cant-capture/src/main.rs}} |
13cf67c4 XL |
481 | ``` |
482 | ||
483 | We get an error: | |
484 | ||
f035d41b | 485 | ```console |
74b04a01 | 486 | {{#include ../listings/ch13-functional-features/no-listing-02-functions-cant-capture/output.txt}} |
13cf67c4 XL |
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 | ||
fc512014 XL |
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 | ||
13cf67c4 XL |
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 | |
74b04a01 | 538 | {{#rustdoc_include ../listings/ch13-functional-features/no-listing-03-move-closures/src/main.rs}} |
13cf67c4 XL |
539 | ``` |
540 | ||
541 | We receive the following error: | |
542 | ||
f035d41b | 543 | ```console |
74b04a01 | 544 | {{#include ../listings/ch13-functional-features/no-listing-03-move-closures/output.txt}} |
13cf67c4 XL |
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. |