-
Notifications
You must be signed in to change notification settings - Fork 13.2k
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
Guide: closures #16206
Guide: closures #16206
Changes from all 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 |
---|---|---|
|
@@ -3642,7 +3642,209 @@ guide](http://doc.rust-lang.org/guide-pointers.html#rc-and-arc). | |
|
||
# Patterns | ||
|
||
# Lambdas | ||
# Closures | ||
|
||
So far, we've made lots of functions in Rust. But we've given them all names. | ||
Rust also allows us to create anonymous functions too. Rust's anonymous | ||
functions are called **closure**s. By themselves, closures aren't all that | ||
interesting, but when you combine them with functions that take closures as | ||
arguments, really powerful things are possible. | ||
|
||
Let's make a closure: | ||
|
||
```{rust} | ||
let add_one = |x| { 1i + x }; | ||
|
||
println!("The 5 plus 1 is {}.", add_one(5i)); | ||
``` | ||
|
||
We create a closure using the `|...| { ... }` syntax, and then we create a | ||
binding so we can use it later. Note that we call the function using the | ||
binding name and two parentheses, just like we would for a named function. | ||
|
||
Let's compare syntax. The two are pretty close: | ||
|
||
```{rust} | ||
let add_one = |x: int| -> int { 1i + x }; | ||
fn add_one (x: int) -> int { 1i + x } | ||
``` | ||
|
||
As you may have noticed, closures infer their argument and return types, so you | ||
don't need to declare one. This is different from named functions, which | ||
default to returning unit (`()`). | ||
|
||
There's one big difference between a closure and named functions, and it's in | ||
the name: a function "closes over its environment." What's that mean? It means | ||
this: | ||
|
||
```{rust} | ||
fn main() { | ||
let x = 5i; | ||
|
||
let printer = || { println!("x is: {}", x); }; | ||
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 think it would be a good idea to explicitly clarify what this is: an anonymous function with no arguments. Then the 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. Agreed. |
||
|
||
printer(); // prints "x is: 5" | ||
} | ||
``` | ||
|
||
The `||` syntax means this is an anonymous closure that takes no arguments. | ||
Without it, we'd just have a block of code in `{}`s. | ||
|
||
In other words, a closure has access to variables in the scope that it's | ||
defined. The closure borrows any variables that it uses. This will error: | ||
|
||
```{rust,ignore} | ||
fn main() { | ||
let mut x = 5i; | ||
|
||
let printer = || { println!("x is: {}", x); }; | ||
|
||
x = 6i; // error: cannot assign to `x` because it is borrowed | ||
} | ||
``` | ||
|
||
## Procs | ||
|
||
Rust has a second type of closure, called a **proc**. Procs are created | ||
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. So: Is like: I don't know if it's a problem but it's definitely weird. 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 don't think it's a problem. You can have a car, and you can also have a |
||
with the `proc` keyword: | ||
|
||
```{rust} | ||
let x = 5i; | ||
|
||
let p = proc() { x * x }; | ||
println!("{}", p()); // prints 25 | ||
``` | ||
|
||
Procs have a big difference from closures: they may only be called once. 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. Implies 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. 'Difference' can be a subtype or a different type. |
||
will error when we try to compile: | ||
|
||
```{rust,ignore} | ||
let x = 5i; | ||
|
||
let p = proc() { x * x }; | ||
println!("{}", p()); | ||
println!("{}", p()); // error: use of moved value `p` | ||
``` | ||
|
||
This restriction is important. Procs are allowed to consume values that they | ||
capture, and thus have to be restricted to being called once for soundness | ||
reasons: any value consumed would be invalid on a second call. | ||
|
||
Procs are most useful with Rust's concurrency features, and so we'll just leave | ||
it at this for now. We'll talk about them more in the "Tasks" section of the | ||
guide. | ||
|
||
## Accepting closures as arguments | ||
|
||
Closures are most useful as an argument to another function. Here's an example: | ||
|
||
```{rust} | ||
fn twice(x: int, f: |int| -> int) -> int { | ||
f(x) + f(x) | ||
} | ||
|
||
fn main() { | ||
let square = |x: int| { x * x }; | ||
|
||
twice(5i, square); // evaluates to 50 | ||
} | ||
``` | ||
|
||
Let's break example down, starting with `main`: | ||
|
||
```{rust} | ||
let square = |x: int| { x * x }; | ||
``` | ||
|
||
We've seen this before. We make a closure that takes an integer, and returns | ||
its square. | ||
|
||
```{rust,ignore} | ||
twice(5i, square); // evaluates to 50 | ||
``` | ||
|
||
This line is more interesting. Here, we call our function, `twice`, and we pass | ||
it two arguments: an integer, `5`, and our closure, `square`. This is just like | ||
passing any other two variable bindings to a function, but if you've never | ||
worked with closures before, it can seem a little complex. Just think: "I'm | ||
passing two variables, one is an int, and one is a function." | ||
|
||
Next, let's look at how `twice` is defined: | ||
|
||
```{rust,ignore} | ||
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. As below, you could do
to keep it valid but hide the non-relevant stuff. (I'm thinking this is important so that the guide is correctly updated with any changes from unboxed 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. Ahhh. I'm going to make a meta-bug for this, as I haven't been doing this in many places in the guide. #16219 |
||
fn twice(x: int, f: |int| -> int) -> int { | ||
``` | ||
|
||
`twice` takes two arguments, `x` and `f`. That's why we called it with two | ||
arguments. `x` is an `int`, we've done that a ton of times. `f` is a function, | ||
though, and that function takes an `int` and returns an `int`. Notice | ||
how the `|int| -> int` syntax looks a lot like our definition of `square` | ||
above, if we added the return type in: | ||
|
||
```{rust} | ||
let square = |x: int| -> int { x * x }; | ||
// |int| -> int | ||
``` | ||
|
||
This function takes an `int` and returns an `int`. | ||
|
||
This is the most complicated function signature we've seen yet! Give it a read | ||
a few times until you can see how it works. It takes a teeny bit of practice, and | ||
then it's easy. | ||
|
||
Finally, `twice` returns an `int` as well. | ||
|
||
Okay, let's look at the body of `twice`: | ||
|
||
```{rust} | ||
fn twice(x: int, f: |int| -> int) -> int { | ||
f(x) + f(x) | ||
} | ||
``` | ||
|
||
Since our closure is named `f`, we can call it just like we called our closures | ||
before. And we pass in our `x` argument to each one. Hence 'twice.' | ||
|
||
If you do the math, `(5 * 5) + (5 * 5) == 50`, so that's the output we get. | ||
|
||
Play around with this concept until you're comfortable with it. Rust's standard | ||
library uses lots of closures, where appropriate, so you'll be using | ||
this technique a lot. | ||
|
||
If we didn't want to give `square` a name, we could also just define it inline. | ||
This example is the same as the previous one: | ||
|
||
```{rust} | ||
fn twice(x: int, f: |int| -> int) -> int { | ||
f(x) + f(x) | ||
} | ||
|
||
fn main() { | ||
twice(5i, |x: int| { x * x }); // evaluates to 50 | ||
} | ||
``` | ||
|
||
A named function's name can be used wherever you'd use a closure. Another | ||
way of writing the previous example: | ||
|
||
```{rust} | ||
fn twice(x: int, f: |int| -> int) -> int { | ||
f(x) + f(x) | ||
} | ||
|
||
fn square(x: int) -> int { x * x } | ||
|
||
fn main() { | ||
twice(5i, square); // evaluates to 50 | ||
} | ||
``` | ||
|
||
Doing this is not particularly common, but every once in a while, it's useful. | ||
|
||
That's all you need to get the hang of closures! Closures are a little bit | ||
strange at first, but once you're used to using them, you'll miss them in any | ||
language that doesn't have them. Passing functions to other functions is | ||
incredibly powerful. Next, let's look at one of those things: iterators. | ||
|
||
# iterators | ||
|
||
|
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.
For the next closure revision:
Kimundi posted here an explanation of the updated closures. This example from his work looks sorta like mixing of those types:
Specifically here it looks like a mixing of the no braces allowance and requiring it. It also looks a little like a pattern guard on a match:
I don't know if it's worth calling out an example like this in the future or not but I wanted to point it out in case it's worth it.