1
1
% Closures
2
2
3
- Rust not only has named functions, but anonymous functions as well. Anonymous
4
- functions that have an associated environment are called ‘closures’, because they
5
- close over an environment. Rust has a really great implementation of them, as
6
- we’ll see.
3
+ Sometimes it is useful to wrap up a function and free variables for better
4
+ clarity and reuse. The _ free variables_ that can be used come from the
5
+ enclosing scope and are "closed over" when used in the function. From this, we
6
+ get the name "closures" and Rust provides a really great implementation of
7
+ them, as we’ll see.
7
8
8
9
# Syntax
9
10
@@ -34,7 +35,7 @@ assert_eq!(4, plus_two(2));
34
35
```
35
36
36
37
You’ll notice a few things about closures that are a bit different from regular
37
- functions defined with ` fn ` . The first is that we did not need to
38
+ named functions defined with ` fn ` . The first is that we did not need to
38
39
annotate the types of arguments the closure takes or the values it returns. We
39
40
can:
40
41
@@ -44,14 +45,14 @@ let plus_one = |x: i32| -> i32 { x + 1 };
44
45
assert_eq! (2 , plus_one (1 ));
45
46
```
46
47
47
- But we don’t have to. Why is this? Basically, it was chosen for ergonomic reasons.
48
- While specifying the full type for named functions is helpful with things like
49
- documentation and type inference, the types of closures are rarely documented
50
- since they’re anonymous, and they don’t cause the kinds of error-at-a-distance
51
- problems that inferring named function types can.
48
+ But we don’t have to. Why is this? Basically, it was chosen for ergonomic
49
+ reasons. While specifying the full type for named functions is helpful with
50
+ things like documentation and type inference, types within closures are rarely
51
+ documented since they’re anonymous, and they don’t cause the kinds of
52
+ error-at-a-distance problems that inferring named function types can.
52
53
53
- The second is that the syntax is similar, but a bit different. I’ve added spaces
54
- here for easier comparison:
54
+ The second is that the syntax is similar, but a bit different. I’ve added
55
+ spaces here for easier comparison:
55
56
56
57
``` rust
57
58
fn plus_one_v1 (x : i32 ) -> i32 { x + 1 }
@@ -63,8 +64,8 @@ Small differences, but they’re similar.
63
64
64
65
# Closures and their environment
65
66
66
- Closures are called such because they ‘close over their environment’. It
67
- looks like this:
67
+ The environment for a closure can include bindings from it's enclosing scope in
68
+ addition to parameters and local bindings. It looks like this:
68
69
69
70
``` rust
70
71
let num = 5 ;
@@ -197,9 +198,10 @@ frame. Without `move`, a closure may be tied to the stack frame that created
197
198
it, while a ` move ` closure is self-contained. This means that you cannot
198
199
generally return a non-` move ` closure from a function, for example.
199
200
200
- But before we talk about taking and returning closures, we should talk some more
201
- about the way that closures are implemented. As a systems language, Rust gives
202
- you tons of control over what your code does, and closures are no different.
201
+ But before we talk about taking and returning closures, we should talk some
202
+ more about the way that closures are implemented. As a systems language, Rust
203
+ gives you tons of control over what your code does, and closures are no
204
+ different.
203
205
204
206
# Closure implementation
205
207
@@ -288,9 +290,9 @@ isn’t interesting. The next part is:
288
290
# some_closure (1 ) }
289
291
```
290
292
291
- Because ` Fn ` is a trait, we can bound our generic with it. In this case, our closure
292
- takes a ` i32 ` as an argument and returns an ` i32 ` , and so the generic bound we use
293
- is ` Fn(i32) -> i32 ` .
293
+ Because ` Fn ` is a trait, we can bound our generic with it. In this case, our
294
+ closure takes a ` i32 ` as an argument and returns an ` i32 ` , and so the generic
295
+ bound we use is ` Fn(i32) -> i32 ` .
294
296
295
297
There’s one other key point here: because we’re bounding a generic with a
296
298
trait, this will get monomorphized, and therefore, we’ll be doing static
0 commit comments