@@ -5,26 +5,26 @@ However, a naive implementation of lifetimes would be either too restrictive,
5
5
or permit undefined behavior.
6
6
7
7
In order to allow flexible usage of lifetimes
8
- while also preventing their misuse, Rust uses a combination of ** Subtyping ** and ** Variance ** .
8
+ while also preventing their misuse, Rust uses ** subtyping ** and ** variance ** .
9
9
10
- Let's start with a example.
10
+ Let's start with an example.
11
11
12
12
``` rust
13
- fn debug <T : std :: fmt :: Debug >(a : T , b : T ) {
13
+ fn debug <' a >(a : & ' a str , b : & ' a str ) {
14
14
println! (" a = {:?} b = {:?}" , a , b );
15
15
}
16
16
17
17
fn main () {
18
18
let hello : & 'static str = " hello" ;
19
19
{
20
20
let world = String :: from (" world" );
21
- let world = & world ; // 'b has a shorter lifetime than 'static
21
+ let world = & world ; // 'world has a shorter lifetime than 'static
22
22
debug (hello , world );
23
23
}
24
24
}
25
25
```
26
26
27
- In a conservative implementation of lifetimes, since ` a ` and ` b ` have differeing lifetimes,
27
+ In a conservative implementation of lifetimes, since ` hello ` and ` world ` have differing lifetimes,
28
28
we might see the following error:
29
29
30
30
``` text
@@ -34,23 +34,25 @@ error[E0308]: mismatched types
34
34
10 | debug(hello, world);
35
35
| ^
36
36
| |
37
- | expected `&'static str`, found struct `&'b str`
37
+ | expected `&'static str`, found struct `&'world str`
38
38
```
39
39
40
40
This would be rather unfortunate. In this case,
41
- what we want is to accept any type that lives * at least as long* as ` 'b ` .
41
+ what we want is to accept any type that lives * at least as long* as ` 'world ` .
42
42
Let's try using subtyping with our lifetimes.
43
43
44
44
## Subtyping
45
45
46
46
Subtyping is the idea that one type can be used in place of another.
47
47
48
- Let's define that ` Sub ` is a subtype of ` Super ` (we'll be using the notation ` Sub: Super ` throughout this chapter)
48
+ Let's define that ` Sub ` is a subtype of ` Super ` (we'll be using the notation ` Sub: Super ` throughout this chapter).
49
49
50
50
What this is suggesting to us is that the set of * requirements* that ` Super ` defines
51
51
are completely satisfied by ` Sub ` . ` Sub ` may then have more requirements.
52
52
53
- An example of simple subtyping that exists in the language are [ supertraits] ( https://doc.rust-lang.org/stable/book/ch19-03-advanced-traits.html?highlight=supertraits#using-supertraits-to-require-one-traits-functionality-within-another-trait )
53
+ An example of simple subtyping that exists in the language is [ supertraits] [ supertraits ] :
54
+
55
+ [ supertraits ] : https://doc.rust-lang.org/book/ch19-03-advanced-traits.html#using-supertraits-to-require-one-traits-functionality-within-another-trait
54
56
55
57
``` rust
56
58
use std :: fmt;
@@ -66,12 +68,15 @@ Here, we have that `Error: fmt::Display` (`Error` is a *subtype* of `Display`),
66
68
because it has all the requirements of ` fmt::Display ` , plus the ` source ` /` description ` /` cause ` functions.
67
69
68
70
However, subtyping in traits is not that interesting.
69
- Here in the nomicon , we're going to focus more with how subtyping interacts with lifetimes
71
+ Here in the Rustonomicon , we're going to focus more with how subtyping interacts with lifetimes.
70
72
71
73
Let's define a lifetime to be the simple requirement:
72
- ` 'a ` defines a region of code in which a value will be alive.
73
- Now that we have a defined set of requirements for lifetimes, we can define how they relate to each other.
74
- ` 'long: 'short ` if and only if ` 'long ` defines a region of code that ** completely contains** ` 'short ` .
74
+
75
+ > ` 'a ` defines a region of code.
76
+
77
+ Now that we have a defined set of requirements for lifetimes, we can define how they relate to each other:
78
+
79
+ > ` 'long : 'short ` if and only if ` 'long ` defines a region of code that ** completely contains** ` 'short ` .
75
80
76
81
` 'long ` may define a region larger than ` 'short ` , but that still fits our definition.
77
82
@@ -83,11 +88,11 @@ And unless you write unsafe code, the compiler will automatically handle all the
83
88
> But this is the Rustonomicon. We're writing unsafe code,
84
89
so we need to understand how this stuff really works, and how we can mess it up.
85
90
86
- Going back to our example above, we can say that ` 'static: 'b ` .
91
+ Going back to our example above, we can say that ` 'static : 'world ` .
87
92
For now, let's also accept the idea that subtypes of lifetimes can be passed through references
88
93
(more on this in [ Variance] ( #variance ) ),
89
- eg. ` &'static str ` is a subtype of ` &'b str ` , then we can let them coerce,
90
- and then the example above will compile
94
+ _ e.g. _ ` &'static str ` is a subtype of ` &'world str ` , then we can let a ` &'static str ` "downgrade" into a ` &'world str ` .
95
+ With that, the example above will compile:
91
96
92
97
``` rust
93
98
fn debug <T : std :: fmt :: Debug >(a : T , b : T ) {
@@ -98,16 +103,16 @@ fn main() {
98
103
let hello : & 'static str = " hello" ;
99
104
{
100
105
let world = String :: from (" world" );
101
- let world = & world ; // 'b has a shorter lifetime than 'static
102
- debug (hello , world ); // a silently converts from `&'static str` into `&'b str`
106
+ let world = & world ; // 'world has a shorter lifetime than 'static
107
+ debug (hello , world ); // hello silently downgrades from `&'static str` into `&'world str`
103
108
}
104
109
}
105
110
```
106
111
107
112
## Variance
108
113
109
- Above, we glossed over the fact that ` 'static: 'b ` implied that ` &'static T: &'b T ` . This uses a property known as variance .
110
- It's not always as simple as this example though, to understand that let's try extend this example a bit
114
+ Above, we glossed over the fact that ` 'static : 'b ` implied that ` &'static T : &'b T ` . This uses a property known as _ variance _ .
115
+ It's not always as simple as this example, though. To understand that, let's try to extend this example a bit:
111
116
112
117
``` rust,compile_fail
113
118
fn assign<T>(input: &mut T, val: T) {
@@ -133,11 +138,11 @@ Our first instinct might be to blame the `assign` impl, but there's really nothi
133
138
It shouldn't be surprising that we might want to assign a ` T ` into a ` T ` .
134
139
135
140
The problem is that we cannot assume that ` &mut &'static str ` and ` &mut &'b str ` are compatible.
136
- This must mean that ` &mut &'static str ` should ** not ** be a * subtype* of ` &mut &'b str ` ,
141
+ This means that ` &mut &'static str ` ** cannot ** be a * subtype* of ` &mut &'b str ` ,
137
142
even if ` 'static ` is a subtype of ` 'b ` .
138
143
139
- Variance is the way that Rust defines the relationships of subtypes through their * type constructor* .
140
- A type constructor is any generic type with unbound arguments .
144
+ Variance is the concept that Rust borrows to define relationships about subtypes through their * type constructor* s .
145
+ A type constructor is any generic item in Rust .
141
146
For instance ` Vec ` is a type constructor that takes a type ` T ` and returns
142
147
` Vec<T> ` . ` & ` and ` &mut ` are type constructors that take two inputs: a
143
148
lifetime, and a type to point to.
@@ -244,15 +249,15 @@ Meanwhile, in the caller we pass in `&mut &'static str` and `&'spike_str str`.
244
249
Because ` &mut T ` is invariant over ` T ` , the compiler concludes it can't apply any subtyping
245
250
to the first argument, and so ` T ` must be exactly ` &'static str ` .
246
251
247
- This is counter to the ` &T ` case
252
+ This is counter to the ` &T ` case:
248
253
249
254
``` rust
250
255
fn debug <T : std :: fmt :: Debug >(a : T , b : T ) {
251
256
println! (" a = {:?} b = {:?}" , a , b );
252
257
}
253
258
```
254
259
255
- Where similarly ` a ` and ` b ` must have the same type ` T ` .
260
+ where similarly ` a ` and ` b ` must have the same type ` T ` .
256
261
But since ` &'a T ` * is* covariant over ` 'a ` , we are allowed to perform subtyping.
257
262
So the compiler decides that ` &'static str ` can become ` &'b str ` if and only if
258
263
` &'static str ` is a subtype of ` &'b str ` , which will hold if ` 'static: 'b ` .
0 commit comments