Skip to content

Commit

Permalink
Clarify the HRTB chapter (#330)
Browse files Browse the repository at this point in the history
  • Loading branch information
fmease authored Jan 22, 2022
1 parent ca00ee8 commit f4d1b42
Showing 1 changed file with 35 additions and 1 deletion.
36 changes: 35 additions & 1 deletion src/hrtb.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,11 @@ fn main() {
```

If we try to naively desugar this code in the same way that we did in the
lifetimes section, we run into some trouble:
[lifetimes section][lt], we run into some trouble:

<!-- ignore: desugared code -->
```rust,ignore
// NOTE: `&'b data.0` and `'x: {` is not valid syntax!
struct Closure<F> {
data: (u8, u16),
func: F,
Expand Down Expand Up @@ -66,10 +67,43 @@ desugar this is as follows:
where for<'a> F: Fn(&'a (u8, u16)) -> &'a u8,
```

Alternatively:

<!-- ignore: simplified code -->
```rust,ignore
where F: for<'a> Fn(&'a (u8, u16)) -> &'a u8,
```

(Where `Fn(a, b, c) -> d` is itself just sugar for the unstable *real* `Fn`
trait)

`for<'a>` can be read as "for all choices of `'a`", and basically produces an
*infinite list* of trait bounds that F must satisfy. Intense. There aren't many
places outside of the `Fn` traits where we encounter HRTBs, and even for
those we have a nice magic sugar for the common cases.

In summary, we can rewrite the original code more explicitly as:

```rust
struct Closure<F> {
data: (u8, u16),
func: F,
}

impl<F> Closure<F>
where for<'a> F: Fn(&'a (u8, u16)) -> &'a u8,
{
fn call(&self) -> &u8 {
(self.func)(&self.data)
}
}

fn do_it(data: &(u8, u16)) -> &u8 { &data.0 }

fn main() {
let clo = Closure { data: (0, 1), func: do_it };
println!("{}", clo.call());
}
```

[lt]: lifetimes.html

0 comments on commit f4d1b42

Please sign in to comment.