-
Notifications
You must be signed in to change notification settings - Fork 13.4k
trpl: Clarify closure terminology #28856
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 2 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,9 +1,10 @@ | ||
% Closures | ||
|
||
Rust not only has named functions, but anonymous functions as well. Anonymous | ||
functions that have an associated environment are called ‘closures’, because they | ||
close over an environment. Rust has a really great implementation of them, as | ||
we’ll see. | ||
Sometimes it is useful to wrap up a function and free variables for better | ||
clarity and reuse. The _free variables_ that can be used come from the | ||
enclosing scope and are "closed over" when used in the function. From this, we | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. these should be single, curly quotes, not double straight quotes |
||
get the name "closures" and Rust provides a really great implementation of | ||
them, as we’ll see. | ||
|
||
# Syntax | ||
|
||
|
@@ -34,7 +35,7 @@ assert_eq!(4, plus_two(2)); | |
``` | ||
|
||
You’ll notice a few things about closures that are a bit different from regular | ||
functions defined with `fn`. The first is that we did not need to | ||
named functions defined with `fn`. The first is that we did not need to | ||
annotate the types of arguments the closure takes or the values it returns. We | ||
can: | ||
|
||
|
@@ -44,14 +45,14 @@ let plus_one = |x: i32| -> i32 { x + 1 }; | |
assert_eq!(2, plus_one(1)); | ||
``` | ||
|
||
But we don’t have to. Why is this? Basically, it was chosen for ergonomic reasons. | ||
While specifying the full type for named functions is helpful with things like | ||
documentation and type inference, the types of closures are rarely documented | ||
since they’re anonymous, and they don’t cause the kinds of error-at-a-distance | ||
problems that inferring named function types can. | ||
But we don’t have to. Why is this? Basically, it was chosen for ergonomic | ||
reasons. While specifying the full type for named functions is helpful with | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. one space after a period please! |
||
things like documentation and type inference, types within closures are rarely | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. "Within" means "in the body to me here", so this seems like a regression. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ahh, I see what you mean there.. maybe it would be better to use one of these?
any thoughts? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. These are also good, but not quite. Like, the issue is that it's about argument and return types, and not the ones in the body. Hrm. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, makes sense, unfortunately the original has an alternate reading that implies that the issue is around multiple kinds of closures There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. How about "the full type signatures of closures are rarely documented"? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I like it. |
||
documented since they’re anonymous, and they don’t cause the kinds of | ||
error-at-a-distance problems that inferring named function types can. | ||
|
||
The second is that the syntax is similar, but a bit different. I’ve added spaces | ||
here for easier comparison: | ||
The second is that the syntax is similar, but a bit different. I’ve added | ||
spaces here for easier comparison: | ||
|
||
```rust | ||
fn plus_one_v1 (x: i32) -> i32 { x + 1 } | ||
|
@@ -63,8 +64,8 @@ Small differences, but they’re similar. | |
|
||
# Closures and their environment | ||
|
||
Closures are called such because they ‘close over their environment’. It | ||
looks like this: | ||
The environment for a closure can include bindings from its enclosing scope in | ||
addition to parameters and local bindings. It looks like this: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. one space after a period! |
||
|
||
```rust | ||
let num = 5; | ||
|
@@ -197,9 +198,10 @@ frame. Without `move`, a closure may be tied to the stack frame that created | |
it, while a `move` closure is self-contained. This means that you cannot | ||
generally return a non-`move` closure from a function, for example. | ||
|
||
But before we talk about taking and returning closures, we should talk some more | ||
about the way that closures are implemented. As a systems language, Rust gives | ||
you tons of control over what your code does, and closures are no different. | ||
But before we talk about taking and returning closures, we should talk some | ||
more about the way that closures are implemented. As a systems language, Rust | ||
gives you tons of control over what your code does, and closures are no | ||
different. | ||
|
||
# Closure implementation | ||
|
||
|
@@ -288,9 +290,9 @@ isn’t interesting. The next part is: | |
# some_closure(1) } | ||
``` | ||
|
||
Because `Fn` is a trait, we can bound our generic with it. In this case, our closure | ||
takes a `i32` as an argument and returns an `i32`, and so the generic bound we use | ||
is `Fn(i32) -> i32`. | ||
Because `Fn` is a trait, we can bound our generic with it. In this case, our | ||
closure takes a `i32` as an argument and returns an `i32`, and so the generic | ||
bound we use is `Fn(i32) -> i32`. | ||
|
||
There’s one other key point here: because we’re bounding a generic with a | ||
trait, this will get monomorphized, and therefore, we’ll be doing static | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would put the hightlight on the first usage rather than the second, I think, but I can't quite say why
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Totally reasonable, probably better to call out the terminology on the first use.