Improve E0311.md description

This commit is contained in:
Matthew Kelly 2022-08-23 05:19:04 -04:00
parent a9cefd0441
commit dbcc409556

View File

@ -21,14 +21,35 @@ where
}
```
In this example we have a trait that borrows some inner data element of type `V`
from an outer type `T`, through an intermediate type `U`. The compiler is unable
to prove that the livetime of `U` is long enough to support the reference. To
fix the issue we can explicitly add lifetime specifiers to the `NestedBorrowMut`
trait, which link the lifetimes of the various data types and allow the code to
compile.
Why doesn't this code compile? The problem has to do with Rust's rules for
lifetime elision in functions (Chapter 10.3 in the Rust book). One of the
inputs is a reference to `self`, so the compiler attempts to assign the
the same lifetime to the `&mut self` input and `&mut V` output to the
`nested_borrow_mut()` function. The problem is that there is no way for the
compiler to directly figure out how these two lifetimes are related in the
implementation of the function. We're implementing the `NextedBorrowMut`
trait for a type `T`, so the `&mut self` reference has the lifetime of `T`.
We know that `T` implements the `BorrowMut` trait returning a reference to `U`,
and that `U` implements the `BorrowMut` trait returning a reference to `V`.
The key is that we have not told the compiler that those two `U` lifetimes
are the same: for all it knows, we could be that the first `BorrowMut` trait
on `T` works with a lifetime `'a` and the second `BorrowMut` trait on `U`
works on a lifetime `'b`.
Working implementation of the `NestedBorrowMut` trait:
The fix here is to add explicit lifetime annotations that tell the compiler
that the lifetime of the output is in fact the same as the lifetime of the
input (`self`). There are three references involved, to objects of type `T`
(`self`), `U` (the intermediate type), and `V` (the return type). In the
working code below, we see that all have been given the same lifetime `'a`:
- `&'a mut self` in the function argument list for `T`
- `U: BorrowMut<V> + 'a` in the trait bounds for `U`
- `&'a mut V` in the function return for `V`.
The compiler can the check that the implementation of the
`nested_borrow_mut()` function satisfies these lifetimes. There are two
functions being called inside of `nested_borrow_mut()`, both of which are
the `borrow_mut()` function, which promises that the output lifetime is
the same as the input lifetime (see lifetime elision rules), which checks out.
```
use std::borrow::BorrowMut;