Clarify lifetimes + trait objects section

Fixes #624.
This commit is contained in:
Carol (Nichols || Goulding)
2018-01-02 15:05:23 -05:00
parent a1e9d3fede
commit 0cc22f2ca2
2 changed files with 51 additions and 42 deletions

View File

@@ -1000,46 +1000,50 @@ references that live forever; both of them are the same for the purpose of
determining whether or not a reference has a shorter lifetime than what it
refers to.
### Trait Object Lifetimes
### Inference of Trait Object Lifetimes
In Chapter 17, we learned about trait objects that consist of putting a trait
behind a reference in order to use dynamic dispatch. However, we didnt discuss
what happens if the type implementing the trait used in the trait object has a
lifetime. Consider Listing 19-19, where we have a trait `Foo` and a struct
`Bar` that holds a reference (and thus has a lifetime parameter) that
implements trait `Foo`, and we want to use an instance of `Bar` as the trait
object `Box<Foo>`:
In Chapter 17, we learned about trait objects, consisting of a trait behind a
reference, that allow us to use dynamic dispatch. We haven't yet discussed what
happens if the type implementing the trait in the trait object has a lifetime
of its own. Consider Listing 19-19, where we have a trait `Red` and a struct
`Ball`. `Ball` holds a reference (and thus has a lifetime parameter) and also
implements trait `Red`. We want to use an instance of `Ball` as the trait
object `Box<Red>`:
Filename: src/main.rs
```
trait Foo { }
trait Red { }
struct Bar<'a> {
x: &'a i32,
struct Ball<'a> {
diameter: &'a i32,
}
impl<'a> Foo for Bar<'a> { }
impl<'a> Red for Ball<'a> { }
let num = 5;
fn main() {
let num = 5;
let obj = Box::new(Bar { x: &num }) as Box<Foo>;
let obj = Box::new(Ball { diameter: &num }) as Box<Red>;
}
```
Listing 19-19: Using a type that has a lifetime parameter with a trait object
This code compiles without any errors, even though we havent said anything
about the lifetimes involved in `obj`. This works because there are rules
having to do with lifetimes and trait objects:
explicit about the lifetimes involved in `obj`. This works because there are
rules having to do with lifetimes and trait objects:
* The default lifetime of a trait object is `'static`.
* If we have `&'a X` or `&'a mut X`, then the default is `'a`.
* If we have a single `T: 'a` clause, then the default is `'a`.
* If we have multiple `T: 'a`-like clauses, then there is no default; we must
* With `&'a Trait` or `&'a mut Trait`, the default lifetime is `'a`.
* With a single `T: 'a` clause, the default lifetime is `'a`.
* With multiple `T: 'a`-like clauses, there is no default; we must
be explicit.
When we must be explicit, we can add a lifetime bound on a trait object like
`Box<Foo>` with the syntax `Box<Foo + 'a>` or `Box<Foo + 'static>`, depending
`Box<Red>` with the syntax `Box<Red + 'a>` or `Box<Red + 'static>`, depending
on whats needed. Just as with the other bounds, this means that any
implementor of the `Foo` trait that has any references inside must have the
implementor of the `Red` trait that has references inside must have the
lifetime specified in the trait object bounds as those references.
Next, lets take a look at some other advanced features dealing with traits!

View File

@@ -421,47 +421,52 @@ references that live forever; both of them are the same for the purpose of
determining whether or not a reference has a shorter lifetime than what it
refers to.
### Trait Object Lifetimes
### Inference of Trait Object Lifetimes
In Chapter 17, we learned about trait objects that consist of putting a trait
behind a reference in order to use dynamic dispatch. However, we didnt discuss
what happens if the type implementing the trait used in the trait object has a
lifetime. Consider Listing 19-19, where we have a trait `Foo` and a struct
`Bar` that holds a reference (and thus has a lifetime parameter) that
implements trait `Foo`, and we want to use an instance of `Bar` as the trait
object `Box<Foo>`:
In Chapter 17 in the “Using Trait Objects that Allow for Values of Different
Types” section, we discussed trait objects, consisting of a trait behind a
reference, that allow us to use dynamic dispatch. We havent yet discussed what
happens if the type implementing the trait in the trait object has a lifetime
of its own. Consider Listing 19-19, where we have a trait `Red` and a struct
`Ball`. `Ball` holds a reference (and thus has a lifetime parameter) and also
implements trait `Red`. We want to use an instance of `Ball` as the trait
object `Box<Red>`:
<span class="filename">Filename: src/main.rs</span>
```rust
trait Foo { }
trait Red { }
struct Bar<'a> {
x: &'a i32,
struct Ball<'a> {
diameter: &'a i32,
}
impl<'a> Foo for Bar<'a> { }
impl<'a> Red for Ball<'a> { }
let num = 5;
fn main() {
let num = 5;
let obj = Box::new(Bar { x: &num }) as Box<Foo>;
let obj = Box::new(Ball { diameter: &num }) as Box<Red>;
}
```
<span class="caption">Listing 19-19: Using a type that has a lifetime parameter
with a trait object</span>
This code compiles without any errors, even though we havent said anything
about the lifetimes involved in `obj`. This works because there are rules
having to do with lifetimes and trait objects:
explicit about the lifetimes involved in `obj`. This works because there are
rules having to do with lifetimes and trait objects:
* The default lifetime of a trait object is `'static`.
* If we have `&'a X` or `&'a mut X`, then the default is `'a`.
* If we have a single `T: 'a` clause, then the default is `'a`.
* If we have multiple `T: 'a`-like clauses, then there is no default; we must
* With `&'a Trait` or `&'a mut Trait`, the default lifetime is `'a`.
* With a single `T: 'a` clause, the default lifetime is `'a`.
* With multiple `T: 'a`-like clauses, there is no default; we must
be explicit.
When we must be explicit, we can add a lifetime bound on a trait object like
`Box<Foo>` with the syntax `Box<Foo + 'a>` or `Box<Foo + 'static>`, depending
`Box<Red>` with the syntax `Box<Red + 'a>` or `Box<Red + 'static>`, depending
on whats needed. Just as with the other bounds, this means that any
implementor of the `Foo` trait that has any references inside must have the
implementor of the `Red` trait that has references inside must have the
lifetime specified in the trait object bounds as those references.
Next, lets take a look at some other advanced features dealing with traits!