diff options
| author | Steve Klabnik <steve@steveklabnik.com> | 2015-09-25 13:33:31 -0600 |
|---|---|---|
| committer | Steve Klabnik <steve@steveklabnik.com> | 2015-09-25 13:33:31 -0600 |
| commit | aed73e0122e538375e6ef827e90c6d1a191c5fff (patch) | |
| tree | 0d9a4417d8909ceb7d587a06d10cba18ec45c461 | |
| parent | de2792faa08943699377f782e86098dda599829a (diff) | |
| parent | 09d4deef5b3f84548c0b9f6e1f70b0f5818eba2d (diff) | |
| download | rust-aed73e0122e538375e6ef827e90c6d1a191c5fff.tar.gz rust-aed73e0122e538375e6ef827e90c6d1a191c5fff.zip | |
Rollup merge of #28588 - critiqjo:trpl-closure, r=steveklabnik
r? @steveklabnik
| -rw-r--r-- | src/doc/trpl/closures.md | 33 |
1 files changed, 17 insertions, 16 deletions
diff --git a/src/doc/trpl/closures.md b/src/doc/trpl/closures.md index 161c4ce90b2..983af4a0efe 100644 --- a/src/doc/trpl/closures.md +++ b/src/doc/trpl/closures.md @@ -411,8 +411,9 @@ fn factory() -> &(Fn(i32) -> i32) { ``` Right. Because we have a reference, we need to give it a lifetime. But -our `factory()` function takes no arguments, so elision doesn’t kick in -here. What lifetime can we choose? `'static`: +our `factory()` function takes no arguments, so +[elision](lifetimes.html#lifetime-elision) doesn’t kick in here. Then what +choices do we have? Try `'static`: ```rust,ignore fn factory() -> &'static (Fn(i32) -> i32) { @@ -432,7 +433,7 @@ But we get another error: ```text error: mismatched types: expected `&'static core::ops::Fn(i32) -> i32`, - found `[closure <anon>:7:9: 7:20]` + found `[closure@<anon>:7:9: 7:20]` (expected &-ptr, found closure) [E0308] |x| x + num @@ -441,21 +442,17 @@ error: mismatched types: ``` This error is letting us know that we don’t have a `&'static Fn(i32) -> i32`, -we have a `[closure <anon>:7:9: 7:20]`. Wait, what? +we have a `[closure@<anon>:7:9: 7:20]`. Wait, what? Because each closure generates its own environment `struct` and implementation of `Fn` and friends, these types are anonymous. They exist just solely for -this closure. So Rust shows them as `closure <anon>`, rather than some +this closure. So Rust shows them as `closure@<anon>`, rather than some autogenerated name. -But why doesn’t our closure implement `&'static Fn`? Well, as we discussed before, -closures borrow their environment. And in this case, our environment is based -on a stack-allocated `5`, the `num` variable binding. So the borrow has a lifetime -of the stack frame. So if we returned this closure, the function call would be -over, the stack frame would go away, and our closure is capturing an environment -of garbage memory! - -So what to do? This _almost_ works: +The error also points out that the return type is expected to be a reference, +but what we are trying to return is not. Further, we cannot directly assign a +`'static` lifetime to an object. So we'll take a different approach and return +a "trait object" by `Box`ing up the `Fn`. This _almost_ works: ```rust,ignore fn factory() -> Box<Fn(i32) -> i32> { @@ -471,7 +468,7 @@ assert_eq!(6, answer); # } ``` -We use a trait object, by `Box`ing up the `Fn`. There’s just one last problem: +There’s just one last problem: ```text error: closure may outlive the current function, but it borrows `num`, @@ -480,8 +477,12 @@ Box::new(|x| x + num) ^~~~~~~~~~~ ``` -We still have a reference to the parent stack frame. With one last fix, we can -make this work: +Well, as we discussed before, closures borrow their environment. And in this +case, our environment is based on a stack-allocated `5`, the `num` variable +binding. So the borrow has a lifetime of the stack frame. So if we returned +this closure, the function call would be over, the stack frame would go away, +and our closure is capturing an environment of garbage memory! With one last +fix, we can make this work: ```rust fn factory() -> Box<Fn(i32) -> i32> { |
