From aa8602e20a95a3b31f23997de59ba8f5f8991420 Mon Sep 17 00:00:00 2001 From: Steve Klabnik Date: Sat, 2 Aug 2014 20:03:36 -0400 Subject: [PATCH] Guide: closures --- src/doc/guide.md | 204 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 203 insertions(+), 1 deletion(-) diff --git a/src/doc/guide.md b/src/doc/guide.md index aab610fb174a7..71bd40ae789ee 100644 --- a/src/doc/guide.md +++ b/src/doc/guide.md @@ -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); }; + + 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 +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 +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} +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