Skip to content

Commit 09d4dee

Browse files
committed
trpl: Refactor returning closures section
1 parent f17cc4c commit 09d4dee

File tree

1 file changed

+17
-16
lines changed

1 file changed

+17
-16
lines changed

src/doc/trpl/closures.md

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -411,8 +411,9 @@ fn factory() -> &(Fn(i32) -> i32) {
411411
```
412412

413413
Right. Because we have a reference, we need to give it a lifetime. But
414-
our `factory()` function takes no arguments, so elision doesn’t kick in
415-
here. What lifetime can we choose? `'static`:
414+
our `factory()` function takes no arguments, so
415+
[elision](lifetimes.html#lifetime-elision) doesn’t kick in here. Then what
416+
choices do we have? Try `'static`:
416417

417418
```rust,ignore
418419
fn factory() -> &'static (Fn(i32) -> i32) {
@@ -432,7 +433,7 @@ But we get another error:
432433
```text
433434
error: mismatched types:
434435
expected `&'static core::ops::Fn(i32) -> i32`,
435-
found `[closure <anon>:7:9: 7:20]`
436+
found `[closure@<anon>:7:9: 7:20]`
436437
(expected &-ptr,
437438
found closure) [E0308]
438439
|x| x + num
@@ -441,21 +442,17 @@ error: mismatched types:
441442
```
442443

443444
This error is letting us know that we don’t have a `&'static Fn(i32) -> i32`,
444-
we have a `[closure <anon>:7:9: 7:20]`. Wait, what?
445+
we have a `[closure@<anon>:7:9: 7:20]`. Wait, what?
445446

446447
Because each closure generates its own environment `struct` and implementation
447448
of `Fn` and friends, these types are anonymous. They exist just solely for
448-
this closure. So Rust shows them as `closure <anon>`, rather than some
449+
this closure. So Rust shows them as `closure@<anon>`, rather than some
449450
autogenerated name.
450451

451-
But why doesn’t our closure implement `&'static Fn`? Well, as we discussed before,
452-
closures borrow their environment. And in this case, our environment is based
453-
on a stack-allocated `5`, the `num` variable binding. So the borrow has a lifetime
454-
of the stack frame. So if we returned this closure, the function call would be
455-
over, the stack frame would go away, and our closure is capturing an environment
456-
of garbage memory!
457-
458-
So what to do? This _almost_ works:
452+
The error also points out that the return type is expected to be a reference,
453+
but what we are trying to return is not. Further, we cannot directly assign a
454+
`'static` lifetime to an object. So we'll take a different approach and return
455+
a "trait object" by `Box`ing up the `Fn`. This _almost_ works:
459456

460457
```rust,ignore
461458
fn factory() -> Box<Fn(i32) -> i32> {
@@ -471,7 +468,7 @@ assert_eq!(6, answer);
471468
# }
472469
```
473470

474-
We use a trait object, by `Box`ing up the `Fn`. There’s just one last problem:
471+
There’s just one last problem:
475472

476473
```text
477474
error: closure may outlive the current function, but it borrows `num`,
@@ -480,8 +477,12 @@ Box::new(|x| x + num)
480477
^~~~~~~~~~~
481478
```
482479

483-
We still have a reference to the parent stack frame. With one last fix, we can
484-
make this work:
480+
Well, as we discussed before, closures borrow their environment. And in this
481+
case, our environment is based on a stack-allocated `5`, the `num` variable
482+
binding. So the borrow has a lifetime of the stack frame. So if we returned
483+
this closure, the function call would be over, the stack frame would go away,
484+
and our closure is capturing an environment of garbage memory! With one last
485+
fix, we can make this work:
485486

486487
```rust
487488
fn factory() -> Box<Fn(i32) -> i32> {

0 commit comments

Comments
 (0)