about summary refs log tree commit diff
path: root/src/doc/trpl/closures.md
blob: 51a0bb69a7ce9291df9959dd084794917de0ec41 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
% 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. Rust's anonymous
functions are called *closures*. 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| { 1 + x };

println!("The sum of 5 plus 1 is {}.", add_one(5));
```

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: i32| -> i32 { 1 + x };
fn  add_one      (x: i32) -> i32 { 1 + 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 closure "closes over its environment." What does that mean? It means
this:

```{rust}
fn main() {
    let x: i32 = 5;

    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 where it's
defined. The closure borrows any variables it uses, so this will error:

```{rust,ignore}
fn main() {
    let mut x: i32 = 5;

    let printer = |&:| { println!("x is: {}", x); };

    x = 6; // error: cannot assign to `x` because it is borrowed
}
```

## Moving closures

Rust has a second type of closure, called a *moving closure*. Moving
closures are indicated using the `move` keyword (e.g., `move || x *
x`). The difference between a moving closure and an ordinary closure
is that a moving closure always takes ownership of all variables that
it uses. Ordinary closures, in contrast, just create a reference into
the enclosing stack frame. Moving closures 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 "Threads" 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<F: Fn(i32) -> i32>(x: i32, f: F) -> i32 {
    f(x) + f(x)
}

fn main() {
    let square = |&: x: i32| { x * x };

    twice(5, square); // evaluates to 50
}
```

Let's break the example down, starting with `main`:

```{rust}
let square = |&: x: i32| { x * x };
```

We've seen this before. We make a closure that takes an integer, and returns
its square.

```{rust}
# fn twice<F: Fn(i32) -> i32>(x: i32, f: F) -> i32 { f(x) + f(x) }
# let square = |&: x: i32| { x * x };
twice(5, 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 i32, and one is a function."

Next, let's look at how `twice` is defined:

```{rust,ignore}
fn twice<F: Fn(i32) -> i32>(x: i32, f: F) -> i32 {
```

`twice` takes two arguments, `x` and `f`. That's why we called it with two
arguments. `x` is an `i32`, we've done that a ton of times. `f` is a function,
though, and that function takes an `i32` and returns an `i32`. This is
what the requirement `Fn(i32) -> i32` for the type parameter `F` says.
You might ask yourself: why do we need to introduce a type parameter here?
That is because in Rust each closure has its own unique type.
So, not only do closures with different signatures have different types,
but different closures with the *same* signature have *different* types!
You can think of it this way: the behaviour of a closure is part of its type.
And since we want to support many different closures that all take
an `i32` and return an `i32` we introduced a type parameter that is able
to represent all these closures. 

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. The good news is that this kind of passing a closure around
can be very efficient. With all the type information available at compile-time
the compiler can do wonders.

Finally, `twice` returns an `i32` as well.

Okay, let's look at the body of `twice`:

```{rust}
fn twice<F: Fn(i32) -> i32>(x: i32, f: F) -> i32 {
  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 the name `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 just define it inline.
This example is the same as the previous one:

```{rust}
fn twice<F: Fn(i32) -> i32>(x: i32, f: F) -> i32 {
    f(x) + f(x)
}

fn main() {
    twice(5, |x: i32| { 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<F: Fn(i32) -> i32>(x: i32, f: F) -> i32 {
    f(x) + f(x)
}

fn square(x: i32) -> i32 { x * x }

fn main() {
    twice(5, square); // evaluates to 50
}
```

Doing this is not particularly common, but it's useful every once in a while.

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 them, you'll miss them
in other languages. Passing functions to other functions is
incredibly powerful, as you will see in the following chapter about iterators.