@@ -9,7 +9,7 @@ while also preventing their misuse, Rust uses a combination of **Subtyping** and
9
9
10
10
## Subtyping
11
11
12
- Subtyping is the idea that one type can be a * subtype * of another.
12
+ Subtyping is the idea that one type can be used in place of another.
13
13
14
14
Let's define that ` Sub ` is a subtype of ` Super ` (we'll be using the notation ` Sub: Super ` throughout this chapter)
15
15
@@ -21,15 +21,15 @@ An example of simple subtyping that exists in the language are [supertraits](htt
21
21
``` rust
22
22
use std :: fmt;
23
23
24
- trait OutlinePrint : fmt :: Display {
25
- fn outline_print (& self ) {
26
- todo! ()
27
- }
24
+ pub trait Error : fmt :: Display {
25
+ fn source (& self ) -> Option < & ( dyn Error + ' static )>;
26
+ fn description ( & self ) -> & str ;
27
+ fn cause ( & self ) -> Option < & dyn Error >;
28
28
}
29
29
```
30
30
31
- Here, we have that ` OutlinePrint : fmt::Display` (` OutlinePrint ` is a * subtype* of ` Display ` ),
32
- because it has all the requirements of ` fmt::Display ` , plus the ` outline_print ` function .
31
+ Here, we have that ` Error : fmt::Display` (` Error ` is a * subtype* of ` Display ` ),
32
+ because it has all the requirements of ` fmt::Display ` , plus the ` source ` / ` description ` / ` cause ` functions .
33
33
34
34
However, subtyping in traits is not that interesting in the case of Rust.
35
35
Here in the nomicon, we're going to focus more with how subtyping interacts with ** lifetimes**
@@ -51,7 +51,7 @@ fn main() {
51
51
}
52
52
```
53
53
54
- In an overly restrictive implementation of lifetimes, since ` a ` and ` b ` have differeing lifetimes,
54
+ In a conservative implementation of lifetimes, since ` a ` and ` b ` have differeing lifetimes,
55
55
we might see the following error:
56
56
57
57
``` text
@@ -64,10 +64,12 @@ error[E0308]: mismatched types
64
64
| expected `&'static str`, found struct `&'b str`
65
65
```
66
66
67
- This is over-restrictive. In this case, what we want is to accept any type that lives * at least as long* as ` 'b ` .
67
+ This would be rather unfortunate. In this case,
68
+ what we want is to accept any type that lives * at least as long* as ` 'b ` .
68
69
Let's try using subtyping with our lifetimes.
69
70
70
- Let's define a lifetime to have the a simple set of requirements: ` 'a ` defines a region of code in which a value will be alive.
71
+ Let's define a lifetime to have the a simple set of requirements:
72
+ ` 'a ` defines a region of code in which a value will be alive.
71
73
Now that we have a defined set of requirements for lifetimes, we can define how they relate to each other.
72
74
` 'a: 'b ` if and only if ` 'a ` defines a region of code that ** completely contains** ` 'b ` .
73
75
@@ -108,20 +110,24 @@ fn main() {
108
110
let world = String::from("world");
109
111
assign(&mut hello, &world);
110
112
}
113
+ println!("{}", hello);
111
114
}
112
115
```
113
116
114
- If this were to compile, this would have a memory bug.
117
+ In ` assign ` , we are setting the ` hello ` reference to point to ` world ` .
118
+ But then ` world ` goes out of scope, before the later use of ` hello ` in the println!
119
+
120
+ This is a classic use-after-free bug!
115
121
116
- If we were to expand this out, we'd see that we're trying to assign a ` &'b str ` into a ` &'static str ` ,
117
- but the problem is that as soon as ` b ` goes out of scope, ` a ` is now invalid, even though it's supposed to have a ` 'static ` lifetime .
122
+ Our first instinct might be to blame the ` assign ` impl, but there's really nothing wrong here.
123
+ It shouldn't be surprising that we might want to assign a ` T ` into a ` T ` .
118
124
119
- However, the implementation of ` assign ` is valid .
120
- Therefore, this must mean that ` &mut &'static str ` should ** not** a * subtype* of ` &mut &'b str ` ,
125
+ The problem is that we cannot assume that ` &mut &'static str ` and ` &mut &'b str ` are compatible .
126
+ This must mean that ` &mut &'static str ` should ** not** be a * subtype* of ` &mut &'b str ` ,
121
127
even if ` 'static ` is a subtype of ` 'b ` .
122
128
123
129
Variance is the way that Rust defines the relationships of subtypes through their * type constructor* .
124
- A type constructor in Rust is any generic type with unbound arguments.
130
+ A type constructor is any generic type with unbound arguments.
125
131
For instance ` Vec ` is a type constructor that takes a type ` T ` and returns
126
132
` Vec<T> ` . ` & ` and ` &mut ` are type constructors that take two inputs: a
127
133
lifetime, and a type to point to.
@@ -190,6 +196,7 @@ fn main() {
190
196
let world = String::from("world");
191
197
assign(&mut hello, &world);
192
198
}
199
+ println!("{}", hello);
193
200
}
194
201
```
195
202
0 commit comments