]>
Commit | Line | Data |
---|---|---|
13cf67c4 XL |
1 | # Trait objects |
2 | ||
3 | > **<sup>Syntax</sup>**\ | |
4 | > _TraitObjectType_ :\ | |
5 | > `dyn`<sup>?</sup> [_TypeParamBounds_] | |
6 | > | |
7 | > _TraitObjectTypeOneBound_ :\ | |
8 | > `dyn`<sup>?</sup> [_TraitBound_] | |
9 | ||
10 | A *trait object* is an opaque value of another type that implements a set of | |
11 | traits. The set of traits is made up of an [object safe] *base trait* plus any | |
12 | number of [auto traits]. | |
13 | ||
14 | Trait objects implement the base trait, its auto traits, and any [supertraits] | |
15 | of the base trait. | |
16 | ||
17 | Trait objects are written as the optional keyword `dyn` followed by a set of | |
18 | trait bounds, but with the following restrictions on the trait bounds. All | |
19 | traits except the first trait must be auto traits, there may not be more than | |
532ac7d7 | 20 | one lifetime, and opt-out bounds (e.g. `?Sized`) are not allowed. Furthermore, |
13cf67c4 XL |
21 | paths to traits may be parenthesized. |
22 | ||
23 | For example, given a trait `Trait`, the following are all trait objects: | |
24 | ||
25 | * `Trait` | |
26 | * `dyn Trait` | |
27 | * `dyn Trait + Send` | |
28 | * `dyn Trait + Send + Sync` | |
29 | * `dyn Trait + 'static` | |
30 | * `dyn Trait + Send + 'static` | |
31 | * `dyn Trait +` | |
32 | * `dyn 'static + Trait`. | |
33 | * `dyn (Trait)` | |
34 | ||
35 | > **Edition Differences**: In the 2015 edition, if the first bound of the | |
36 | > trait object is a path that starts with `::`, then the `dyn` will be treated | |
37 | > as a part of the path. The first path can be put in parenthesis to get | |
38 | > around this. As such, if you want a trait object with the trait | |
39 | > `::your_module::Trait`, you should write it as `dyn (::your_module::Trait)`. | |
40 | > | |
41 | > Beginning in the 2018 edition, `dyn` is a true keyword and is not allowed in | |
42 | > paths, so the parentheses are not necessary. | |
43 | ||
44 | > Note: For clarity, it is recommended to always use the `dyn` keyword on your | |
45 | > trait objects unless your codebase supports compiling with Rust 1.26 or lower. | |
46 | ||
47 | Two trait object types alias each other if the base traits alias each other and | |
48 | if the sets of auto traits are the same and the lifetime bounds are the same. | |
49 | For example, `dyn Trait + Send + UnwindSafe` is the same as | |
50 | `dyn Trait + Unwindsafe + Send`. | |
51 | ||
52 | <div class="warning"> | |
53 | ||
54 | ***Warning:*** With two trait object types, even when the complete set of traits | |
55 | is the same, if the base traits differ, the type is different. For example, | |
56 | `dyn Send + Sync` is a different type from `dyn Sync + Send`. See [issue 33140]. | |
57 | ||
58 | </div> | |
59 | ||
60 | Due to the opaqueness of which concrete type the value is of, trait objects are | |
61 | [dynamically sized types]. Like all | |
62 | <abbr title="dynamically sized types">DSTs</abbr>, trait objects are used | |
63 | behind some type of pointer; for example `&dyn SomeTrait` or | |
64 | `Box<dyn SomeTrait>`. Each instance of a pointer to a trait object includes: | |
65 | ||
66 | - a pointer to an instance of a type `T` that implements `SomeTrait` | |
67 | - a _virtual method table_, often just called a _vtable_, which contains, for | |
68 | each method of `SomeTrait` and its [supertraits] that `T` implements, a | |
69 | pointer to `T`'s implementation (i.e. a function pointer). | |
70 | ||
71 | The purpose of trait objects is to permit "late binding" of methods. Calling a | |
72 | method on a trait object results in virtual dispatch at runtime: that is, a | |
73 | function pointer is loaded from the trait object vtable and invoked indirectly. | |
74 | The actual implementation for each vtable entry can vary on an object-by-object | |
75 | basis. | |
76 | ||
77 | An example of a trait object: | |
78 | ||
79 | ```rust | |
80 | trait Printable { | |
81 | fn stringify(&self) -> String; | |
82 | } | |
83 | ||
84 | impl Printable for i32 { | |
85 | fn stringify(&self) -> String { self.to_string() } | |
86 | } | |
87 | ||
88 | fn print(a: Box<dyn Printable>) { | |
89 | println!("{}", a.stringify()); | |
90 | } | |
91 | ||
92 | fn main() { | |
93 | print(Box::new(10) as Box<dyn Printable>); | |
94 | } | |
95 | ``` | |
96 | ||
97 | In this example, the trait `Printable` occurs as a trait object in both the | |
98 | type signature of `print`, and the cast expression in `main`. | |
99 | ||
100 | ## Trait Object Lifetime Bounds | |
101 | ||
102 | Since a trait object can contain references, the lifetimes of those references | |
103 | need to be expressed as part of the trait object. This lifetime is written as | |
104 | `Trait + 'a`. There are [defaults] that allow this lifetime to usually be | |
105 | inferred with a sensible choice. | |
106 | ||
416331ca XL |
107 | [_TraitBound_]: ../trait-bounds.md |
108 | [_TypeParamBounds_]: ../types.md#type-expressions | |
109 | [auto traits]: ../special-types-and-traits.md#auto-traits | |
110 | [defaults]: ../lifetime-elision.md#default-trait-object-lifetimes | |
111 | [dynamically sized types]: ../dynamically-sized-types.md | |
13cf67c4 | 112 | [issue 33140]: https://github.com/rust-lang/rust/issues/33140 |
416331ca XL |
113 | [object safe]: ../items/traits.md#object-safety |
114 | [supertraits]: ../items/traits.md#supertraits |