Skip to content

Commit 011f612

Browse files
committed
explain in more depth
1 parent 15d40b3 commit 011f612

File tree

1 file changed

+3
-1
lines changed

1 file changed

+3
-1
lines changed

posts/2024-09-05-impl-trait-capture-rules.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,9 @@ fn process<'c, T> {
102102
}
103103
```
104104

105-
Here the `process` function applies `context.process` to each of the elements in `datums` (of type `T`). Because the return value uses `context`, it is declared as `+ 'c`. Our real goal here is to allow the return type to use `'c`; writing `+ 'c` achieves that goal because `'c` not appears in the bound listing. However, writing `+ 'c` *also* means that the hidden type must outlive `'c` -- and in this case, that is not strictly necessary! The hidden type is going to be a wrapper around `std::vec::IntoIter<T>`, and for this type to outlive `'c`, we would need a where clause `T: 'c`. But that where-clause should only be required if we use a value of type `&'c T`, and we don't. The result is that this example doe snot compile ([try it on the playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=b742fbf9b083a6e837db0b170489f34a)), even though it should.
105+
Here the `process` function applies `context.process` to each of the elements in `datums` (of type `T`). Because the return value uses `context`, it is declared as `+ 'c`. Our real goal here is to allow the return type to use `'c`; writing `+ 'c` achieves that goal because `'c` not appears in the bound listing. However, while writing `+ 'c` is a convenient way to make `'c` appear in the bounds, also means that the hidden type must outlive `'c`. This requirement is not needed and will in fact lead to a compilation error in this example ([try it on the playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=b742fbf9b083a6e837db0b170489f34a)).
106+
107+
The reason that this error occurs is a bit subtle. The hidden type is an iterator type based on the result of `datums.into_iter()`, which will include the type `T`. Because of the `+ 'c` bound, the hidden type must outlive `'c`, which in turn means that `T` must outlive `'c`. But `T` is a generic parameter, so the compiler requires a where-clause like `where T: 'c`. This where-clause means "it is safe to create a reference with lifetime `'c` to the type `T`". But in fact we don't create any such reference, so the where-clause should not be needed. It is only needed because used the convenient-but-sometimes-incorrect workaround of adding `+ 'c` to the bounds of our `impl Trait`.
106108

107109
Just as before, this error is obscure, touching on the more complex aspects of Rust's type system. Unlike before, there is no easy fix! This problem in fact occurred frequently in the compiler, leading to an [obscure workaround called the `Captures` trait](https://github.com/rust-lang/rust/issues/34511#issuecomment-373423999). Gross!
108110

0 commit comments

Comments
 (0)