@@ -10,7 +10,7 @@ interface consists of [associated items], which come in three varieties:
10
10
All traits define an implicit type parameter ` Self ` that refers to "the type
11
11
that is implementing this interface". Traits may also contain additional type
12
12
parameters. These type parameters (including ` Self ` ) may be constrained by
13
- other traits and so forth as usual.
13
+ other traits and so forth [ as usual] .
14
14
15
15
Traits are implemented for specific types through separate [ implementations] .
16
16
@@ -48,71 +48,72 @@ Object safe traits can be the base trait of a [trait object]. A trait is
48
48
and
49
49
* Be a [ method] that does not use ` Self ` except in the type of the receiver.
50
50
* It must not have any associated constants.
51
+ * All supertraits must also be object safe.
51
52
52
53
## Supertraits
53
54
54
- Trait bounds on ` Self ` are considered "supertraits". These are required to be
55
- acyclic. Supertraits are somewhat different from other constraints in that
56
- they affect what methods are available in the vtable when the trait is used as
57
- a [ trait object] . Consider the following example:
55
+ ** Supertraits** are traits that are required to be implemented for a type to
56
+ implement a specific trait. Furthermore, anywhere a [ generic] or [ trait object]
57
+ is bounded by a trait, it has access to the associated items of its supertraits.
58
+
59
+ Supertraits are declared by trait bounds on the ` Self ` type of a trait and
60
+ transitively the supertraits of the traits declared in those trait bounds. It is
61
+ an error for a trait to be its own supertrait.
62
+
63
+ The following is an example of declaring ` Shape ` to be a supertrait of ` Circle ` .
58
64
59
65
``` rust
60
66
trait Shape { fn area (& self ) -> f64 ; }
61
67
trait Circle : Shape { fn radius (& self ) -> f64 ; }
62
68
```
63
69
64
- The syntax ` Circle : Shape ` means that types that implement ` Circle ` must also
65
- have an implementation for ` Shape ` . Multiple supertraits are separated by ` + ` ,
66
- ` trait Circle : Shape + PartialEq { } ` . In an implementation of ` Circle ` for a
67
- given type ` T ` , methods can refer to ` Shape ` methods, since the typechecker
68
- checks that any type with an implementation of ` Circle ` also has an
69
- implementation of ` Shape ` :
70
+ And the following is the same example, except using [ where clauses] .
70
71
71
72
``` rust
72
- struct Foo ;
73
-
74
73
trait Shape { fn area (& self ) -> f64 ; }
75
- trait Circle : Shape { fn radius (& self ) -> f64 ; }
76
- impl Shape for Foo {
77
- fn area (& self ) -> f64 {
78
- 0.0
79
- }
80
- }
81
- impl Circle for Foo {
82
- fn radius (& self ) -> f64 {
83
- println! (" calling area: {}" , self . area ());
74
+ trait Circle where Self : Shape { fn radius (& self ) -> f64 ; }
75
+ ```
76
+
77
+ This next example gives ` radius ` a default implementation using the ` area `
78
+ function from ` Shape ` .
84
79
85
- 0.0
80
+ ``` rust
81
+ # trait Shape { fn area (& self ) -> f64 ; }
82
+ trait Circle where Self : Shape {
83
+ fn radius (& self ) -> f64 {
84
+ // A = pi * r^2
85
+ // so algebraically,
86
+ // r = sqrt(A / pi)
87
+ (self . area () / std :: f64 :: consts :: PI ). sqrt ()
86
88
}
87
89
}
88
-
89
- let c = Foo ;
90
- c . radius ();
91
90
```
92
91
93
92
In type-parameterized functions, methods of the supertrait may be called on
94
- values of subtrait-bound type parameters. Referring to the previous example of
93
+ values of subtrait-bound type parameters. Continuing the example of
95
94
` trait Circle : Shape ` :
96
95
97
96
``` rust
98
97
# trait Shape { fn area (& self ) -> f64 ; }
99
98
# trait Circle : Shape { fn radius (& self ) -> f64 ; }
100
- fn radius_times_area <T : Circle >(c : T ) -> f64 {
101
- // `c` is both a Circle and a Shape
102
- c . radius () * c . area ()
99
+ fn print_area_and_radius <C : Circle >(c : C ) {
100
+ // Here we call the area method from the supertrait `Shape` of `Circle`.
101
+ println! (" Area: {}" , c . area ());
102
+ println! (" Radius: {}" , c . radius ());
103
103
}
104
104
```
105
105
106
- Likewise, supertrait methods may also be called on trait objects.
106
+ Likewise, here is an example of calling supertrait methods on trait objects.
107
107
108
108
``` rust
109
109
# trait Shape { fn area (& self ) -> f64 ; }
110
110
# trait Circle : Shape { fn radius (& self ) -> f64 ; }
111
+ # struct UnitCircle ;
111
112
# impl Shape for i32 { fn area (& self ) -> f64 { 0.0 } }
112
113
# impl Circle for i32 { fn radius (& self ) -> f64 { 0.0 } }
113
114
# let mycircle = 0i32 ;
114
- let mycircle = Box :: new (mycircle ) as Box <Circle >;
115
- let nonsense = mycircle . radius () * mycircle . area ();
115
+ let circle = Box :: new (mycircle ) as Box <dyn Circle >;
116
+ let nonsense = circle . radius () * circle . area ();
116
117
```
117
118
118
119
[ bounds ] : trait-bounds.html
@@ -121,4 +122,6 @@ let nonsense = mycircle.radius() * mycircle.area();
121
122
[ RFC 255 ] : https://github.com/rust-lang/rfcs/blob/master/text/0255-object-safety.md
122
123
[ associated items ] : items/associated-items.html
123
124
[ method ] : items/associated-items.html#methods
124
- [ implementations ] : items/implementations.html
125
+ [ implementations ] : items/implementations.html
126
+ [ as usual ] : items/generics.html
127
+ [ where clauses ] : items/generics.html#where-clauses
0 commit comments