Skip to content

Commit 8160fc4

Browse files
committed
Auto merge of rust-lang#21078 - js-ojus:master, r=steveklabnik
* Include an illustration of a function that accepts two closures.
2 parents b7930d9 + ac110df commit 8160fc4

File tree

1 file changed

+35
-8
lines changed

1 file changed

+35
-8
lines changed

src/doc/trpl/closures.md

+35-8
Original file line numberDiff line numberDiff line change
@@ -117,14 +117,7 @@ fn twice<F: Fn(i32) -> i32>(x: i32, f: F) -> i32 {
117117
arguments. `x` is an `i32`, we've done that a ton of times. `f` is a function,
118118
though, and that function takes an `i32` and returns an `i32`. This is
119119
what the requirement `Fn(i32) -> i32` for the type parameter `F` says.
120-
You might ask yourself: why do we need to introduce a type parameter here?
121-
That is because in Rust each closure has its own unique type.
122-
So, not only do closures with different signatures have different types,
123-
but different closures with the *same* signature have *different* types!
124-
You can think of it this way: the behaviour of a closure is part of its type.
125-
And since we want to support many different closures that all take
126-
an `i32` and return an `i32` we introduced a type parameter that is able
127-
to represent all these closures.
120+
Now `F` represents *any* function that takes an `i32` and returns an `i32`.
128121

129122
This is the most complicated function signature we've seen yet! Give it a read
130123
a few times until you can see how it works. It takes a teeny bit of practice, and
@@ -181,6 +174,40 @@ fn main() {
181174

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

177+
Before we move on, let us look at a function that accepts two closures.
178+
179+
```{rust}
180+
fn compose<F, G>(x: i32, f: F, g: G) -> i32
181+
where F: Fn(i32) -> i32, G: Fn(i32) -> i32 {
182+
g(f(x))
183+
}
184+
185+
fn main() {
186+
compose(5,
187+
|&: n: i32| { n + 42 },
188+
|&: n: i32| { n * 2 }); // evaluates to 94
189+
}
190+
```
191+
192+
You might ask yourself: why do we need to introduce two type
193+
parameters `F` and `G` here? Evidently, both `f` and `g` have the
194+
same signature: `Fn(i32) -> i32`.
195+
196+
That is because in Rust each closure has its own unique type.
197+
So, not only do closures with different signatures have different types,
198+
but different closures with the *same* signature have *different*
199+
types, as well!
200+
201+
You can think of it this way: the behavior of a closure is part of its
202+
type. Therefore, using a single type parameter for both closures
203+
will accept the first of them, rejecting the second. The distinct
204+
type of the second closure does not allow it to be represented by the
205+
same type parameter as that of the first. We acknowledge this, and
206+
use two different type parameters `F` and `G`.
207+
208+
This also introduces the `where` clause, which lets us describe type
209+
parameters in a more flexible manner.
210+
184211
That's all you need to get the hang of closures! Closures are a little bit
185212
strange at first, but once you're used to them, you'll miss them
186213
in other languages. Passing functions to other functions is

0 commit comments

Comments
 (0)