]>
Commit | Line | Data |
---|---|---|
e74abb32 XL |
1 | # Type system attributes |
2 | ||
3 | The following [attributes] are used for changing how a type can be used. | |
4 | ||
5 | ## The `non_exhaustive` attribute | |
6 | ||
7 | The *`non_exhaustive` attribute* indicates that a type or variant may have | |
8 | more fields or variants added in the future. It can be applied to | |
9 | [`struct`s][struct], [`enum`s][enum], and `enum` variants. | |
10 | ||
11 | The `non_exhaustive` attribute uses the [_MetaWord_] syntax and thus does not | |
12 | take any inputs. | |
13 | ||
14 | Within the defining crate, `non_exhaustive` has no effect. | |
15 | ||
16 | ```rust | |
17 | #[non_exhaustive] | |
18 | pub struct Config { | |
19 | pub window_width: u16, | |
20 | pub window_height: u16, | |
21 | } | |
22 | ||
23 | #[non_exhaustive] | |
24 | pub enum Error { | |
25 | Message(String), | |
26 | Other, | |
27 | } | |
28 | ||
29 | pub enum Message { | |
30 | #[non_exhaustive] Send { from: u32, to: u32, contents: String }, | |
31 | #[non_exhaustive] Reaction(u32), | |
32 | #[non_exhaustive] Quit, | |
33 | } | |
34 | ||
35 | // Non-exhaustive structs can be constructed as normal within the defining crate. | |
36 | let config = Config { window_width: 640, window_height: 480 }; | |
37 | ||
38 | // Non-exhaustive structs can be matched on exhaustively within the defining crate. | |
39 | if let Config { window_width, window_height } = config { | |
40 | // ... | |
41 | } | |
42 | ||
43 | let error = Error::Other; | |
44 | let message = Message::Reaction(3); | |
45 | ||
46 | // Non-exhaustive enums can be matched on exhaustively within the defining crate. | |
47 | match error { | |
48 | Error::Message(ref s) => { }, | |
49 | Error::Other => { }, | |
50 | } | |
51 | ||
52 | match message { | |
53 | // Non-exhaustive variants can be matched on exhaustively within the defining crate. | |
54 | Message::Send { from, to, contents } => { }, | |
55 | Message::Reaction(id) => { }, | |
56 | Message::Quit => { }, | |
57 | } | |
58 | ``` | |
59 | ||
60 | Outside of the defining crate, types annotated with `non_exhaustive` have limitations that | |
61 | preserve backwards compatibility when new fields or variants are added. | |
62 | ||
63 | Non-exhaustive types cannot be constructed outside of the defining crate: | |
64 | ||
65 | - Non-exhaustive variants ([`struct`][struct] or [`enum` variant][enum]) cannot be constructed | |
66 | with a [_StructExpression_] \(including with [functional update syntax]). | |
67 | - [`enum`][enum] instances can be constructed in an [_EnumerationVariantExpression_]. | |
68 | ||
60c5eb7d XL |
69 | <!-- ignore: requires external crates --> |
70 | ```rust,ignore | |
e74abb32 XL |
71 | // `Config`, `Error`, and `Message` are types defined in an upstream crate that have been |
72 | // annotated as `#[non_exhaustive]`. | |
73 | use upstream::{Config, Error, Message}; | |
74 | ||
75 | // Cannot construct an instance of `Config`, if new fields were added in | |
76 | // a new version of `upstream` then this would fail to compile, so it is | |
77 | // disallowed. | |
78 | let config = Config { window_width: 640, window_height: 480 }; | |
79 | ||
80 | // Can construct an instance of `Error`, new variants being introduced would | |
81 | // not result in this failing to compile. | |
82 | let error = Error::Message("foo".to_string()); | |
83 | ||
84 | // Cannot construct an instance of `Message::Send` or `Message::Reaction`, | |
85 | // if new fields were added in a new version of `upstream` then this would | |
86 | // fail to compile, so it is disallowed. | |
87 | let message = Message::Send { from: 0, to: 1, contents: "foo".to_string(), }; | |
88 | let message = Message::Reaction(0); | |
89 | ||
90 | // Cannot construct an instance of `Message::Quit`, if this were converted to | |
91 | // a tuple-variant `upstream` then this would fail to compile. | |
92 | let message = Message::Quit; | |
93 | ``` | |
94 | ||
95 | There are limitations when matching on non-exhaustive types outside of the defining crate: | |
96 | ||
97 | - When pattern matching on a non-exhaustive variant ([`struct`][struct] or [`enum` variant][enum]), | |
98 | a [_StructPattern_] must be used which must include a `..`. Tuple variant constructor visibility | |
99 | is lowered to `min($vis, pub(crate))`. | |
100 | - When pattern matching on a non-exhaustive [`enum`][enum], matching on a variant does not | |
101 | contribute towards the exhaustiveness of the arms. | |
102 | ||
60c5eb7d XL |
103 | <!-- ignore: requires external crates --> |
104 | ```rust, ignore | |
e74abb32 XL |
105 | // `Config`, `Error`, and `Message` are types defined in an upstream crate that have been |
106 | // annotated as `#[non_exhaustive]`. | |
107 | use upstream::{Config, Error, Message}; | |
108 | ||
109 | // Cannot match on a non-exhaustive enum without including a wildcard arm. | |
110 | match error { | |
111 | Error::Message(ref s) => { }, | |
112 | Error::Other => { }, | |
113 | // would compile with: `_ => {},` | |
114 | } | |
115 | ||
116 | // Cannot match on a non-exhaustive struct without a wildcard. | |
117 | if let Ok(Config { window_width, window_height }) = config { | |
118 | // would compile with: `..` | |
119 | } | |
120 | ||
121 | match message { | |
122 | // Cannot match on a non-exhaustive struct enum variant without including a wildcard. | |
123 | Message::Send { from, to, contents } => { }, | |
124 | // Cannot match on a non-exhaustive tuple or unit enum variant. | |
125 | Message::Reaction(type) => { }, | |
126 | Message::Quit => { }, | |
127 | } | |
128 | ``` | |
129 | ||
130 | Non-exhaustive types are always considered inhabited in downstream crates. | |
131 | ||
132 | [_EnumerationVariantExpression_]: ../expressions/enum-variant-expr.md | |
133 | [_MetaWord_]: ../attributes.md#meta-item-attribute-syntax | |
134 | [_StructExpression_]: ../expressions/struct-expr.md | |
135 | [_StructPattern_]: ../patterns.md#struct-patterns | |
136 | [_TupleStructPattern_]: ../patterns.md#tuple-struct-patterns | |
137 | [`if let`]: ../expressions/if-expr.md#if-let-expressions | |
138 | [`match`]: ../expressions/match-expr.md | |
139 | [attributes]: ../attributes.md | |
140 | [enum]: ../items/enumerations.md | |
141 | [functional update syntax]: ../expressions/struct-expr.md#functional-update-syntax | |
142 | [struct]: ../items/structs.md |