Skip to content

Commit 1516893

Browse files
committed
Rollup merge of #28856 - chills42:master, r=steveklabnik
This is to address issue #28803 by improving some of the references to closures, to explain what they are more clearly, while hopefully still being concise. r? @steveklabnik
2 parents a5f3f89 + 7895ec2 commit 1516893

File tree

1 file changed

+24
-21
lines changed

1 file changed

+24
-21
lines changed

src/doc/trpl/closures.md

Lines changed: 24 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
% Closures
22

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.
78

89
# Syntax
910

@@ -34,7 +35,7 @@ assert_eq!(4, plus_two(2));
3435
```
3536

3637
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
3839
annotate the types of arguments the closure takes or the values it returns. We
3940
can:
4041

@@ -44,14 +45,15 @@ let plus_one = |x: i32| -> i32 { x + 1 };
4445
assert_eq!(2, plus_one(1));
4546
```
4647

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, the full type signatures of
51+
closures are rarely documented since they’re anonymous, and they don’t cause
52+
the kinds of error-at-a-distance problems that inferring named function types
53+
can.
5254

53-
The second is that the syntax is similar, but a bit different. I’ve added spaces
54-
here for easier comparison:
55+
The second is that the syntax is similar, but a bit different. I’ve added
56+
spaces here for easier comparison:
5557

5658
```rust
5759
fn plus_one_v1 (x: i32) -> i32 { x + 1 }
@@ -63,8 +65,8 @@ Small differences, but they’re similar.
6365

6466
# Closures and their environment
6567

66-
Closures are called such because they ‘close over their environment’. It
67-
looks like this:
68+
The environment for a closure can include bindings from its enclosing scope in
69+
addition to parameters and local bindings. It looks like this:
6870

6971
```rust
7072
let num = 5;
@@ -197,9 +199,10 @@ frame. Without `move`, a closure may be tied to the stack frame that created
197199
it, while a `move` closure is self-contained. This means that you cannot
198200
generally return a non-`move` closure from a function, for example.
199201

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.
202+
But before we talk about taking and returning closures, we should talk some
203+
more about the way that closures are implemented. As a systems language, Rust
204+
gives you tons of control over what your code does, and closures are no
205+
different.
203206

204207
# Closure implementation
205208

@@ -288,9 +291,9 @@ isn’t interesting. The next part is:
288291
# some_closure(1) }
289292
```
290293

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`.
294+
Because `Fn` is a trait, we can bound our generic with it. In this case, our
295+
closure takes a `i32` as an argument and returns an `i32`, and so the generic
296+
bound we use is `Fn(i32) -> i32`.
294297

295298
There’s one other key point here: because we’re bounding a generic with a
296299
trait, this will get monomorphized, and therefore, we’ll be doing static
@@ -452,7 +455,7 @@ autogenerated name.
452455
The error also points out that the return type is expected to be a reference,
453456
but what we are trying to return is not. Further, we cannot directly assign a
454457
`'static` lifetime to an object. So we'll take a different approach and return
455-
a "trait object" by `Box`ing up the `Fn`. This _almost_ works:
458+
a trait object by `Box`ing up the `Fn`. This _almost_ works:
456459

457460
```rust,ignore
458461
fn factory() -> Box<Fn(i32) -> i32> {

0 commit comments

Comments
 (0)