diff options
| author | JONNALAGADDA Srinivas <js@ojuslabs.com> | 2015-01-13 10:14:18 +0530 |
|---|---|---|
| committer | JONNALAGADDA Srinivas <js@ojuslabs.com> | 2015-01-13 10:14:18 +0530 |
| commit | ac110df0ff52c3ae93d98bc75ec08b99d7d205b5 (patch) | |
| tree | 0a2e4d58ca37e712d0c05855780810e123d27d6a | |
| parent | 3d5fbae33897a8340542f21b6ded913148ca9199 (diff) | |
| download | rust-ac110df0ff52c3ae93d98bc75ec08b99d7d205b5.tar.gz rust-ac110df0ff52c3ae93d98bc75ec08b99d7d205b5.zip | |
Expand the section on closures in TRPL.
* Include an illustration of a function that accepts two closures.
| -rw-r--r-- | src/doc/trpl/closures.md | 43 |
1 files changed, 35 insertions, 8 deletions
diff --git a/src/doc/trpl/closures.md b/src/doc/trpl/closures.md index 5b49df92fe3..3f78e0151bc 100644 --- a/src/doc/trpl/closures.md +++ b/src/doc/trpl/closures.md @@ -117,14 +117,7 @@ fn twice<F: Fn(i32) -> i32>(x: i32, f: F) -> i32 { 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. +Now `F` represents *any* function that takes an `i32` and returns an `i32`. 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 @@ -181,6 +174,40 @@ fn main() { Doing this is not particularly common, but it's useful every once in a while. +Before we move on, let us look at a function that accepts two closures. + +```{rust} +fn compose<F, G>(x: i32, f: F, g: G) -> i32 + where F: Fn(i32) -> i32, G: Fn(i32) -> i32 { + g(f(x)) +} + +fn main() { + compose(5, + |&: n: i32| { n + 42 }, + |&: n: i32| { n * 2 }); // evaluates to 94 +} +``` + +You might ask yourself: why do we need to introduce two type +parameters `F` and `G` here? Evidently, both `f` and `g` have the +same signature: `Fn(i32) -> i32`. + +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, as well! + +You can think of it this way: the behavior of a closure is part of its +type. Therefore, using a single type parameter for both closures +will accept the first of them, rejecting the second. The distinct +type of the second closure does not allow it to be represented by the +same type parameter as that of the first. We acknowledge this, and +use two different type parameters `F` and `G`. + +This also introduces the `where` clause, which lets us describe type +parameters in a more flexible manner. + 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 |
