Type system attributes
The following attributes are used for changing how a type can be used.
The non_exhaustive
attribute
The non_exhaustive
attribute indicates that a type or variant may have more fields or variants added in the future. It can be applied to struct
s, enum
s, and enum
variants.
The non_exhaustive
attribute uses the MetaWord syntax and thus does not take any inputs.
Within the defining crate, non_exhaustive
has no effect.
#![allow(unused)] fn main() { #[non_exhaustive] pub struct Config { pub window_width: u16, pub window_height: u16, } #[non_exhaustive] pub enum Error { Message(String), Other, } pub enum Message { #[non_exhaustive] Send { from: u32, to: u32, contents: String }, #[non_exhaustive] Reaction(u32), #[non_exhaustive] Quit, } // Non-exhaustive structs can be constructed as normal within the defining crate. let config = Config { window_width: 640, window_height: 480 }; // Non-exhaustive structs can be matched on exhaustively within the defining crate. if let Config { window_width, window_height } = config { // ... } let error = Error::Other; let message = Message::Reaction(3); // Non-exhaustive enums can be matched on exhaustively within the defining crate. match error { Error::Message(ref s) => { }, Error::Other => { }, } match message { // Non-exhaustive variants can be matched on exhaustively within the defining crate. Message::Send { from, to, contents } => { }, Message::Reaction(id) => { }, Message::Quit => { }, } }
Outside of the defining crate, types annotated with non_exhaustive
have limitations that preserve backwards compatibility when new fields or variants are added.
Non-exhaustive types cannot be constructed outside of the defining crate:
- Non-exhaustive variants (
struct
orenum
variant) cannot be constructed with a StructExpression (including with functional update syntax). -
enum
instances can be constructed.
// `Config`, `Error`, and `Message` are types defined in an upstream crate that have been // annotated as `#[non_exhaustive]`. use upstream::{Config, Error, Message}; // Cannot construct an instance of `Config`, if new fields were added in // a new version of `upstream` then this would fail to compile, so it is // disallowed. let config = Config { window_width: 640, window_height: 480 }; // Can construct an instance of `Error`, new variants being introduced would // not result in this failing to compile. let error = Error::Message("foo".to_string()); // Cannot construct an instance of `Message::Send` or `Message::Reaction`, // if new fields were added in a new version of `upstream` then this would // fail to compile, so it is disallowed. let message = Message::Send { from: 0, to: 1, contents: "foo".to_string(), }; let message = Message::Reaction(0); // Cannot construct an instance of `Message::Quit`, if this were converted to // a tuple-variant `upstream` then this would fail to compile. let message = Message::Quit;
There are limitations when matching on non-exhaustive types outside of the defining crate:
- When pattern matching on a non-exhaustive variant (
struct
orenum
variant), a StructPattern must be used which must include a..
. Tuple variant constructor visibility is lowered tomin($vis, pub(crate))
. - When pattern matching on a non-exhaustive
enum
, matching on a variant does not contribute towards the exhaustiveness of the arms.
// `Config`, `Error`, and `Message` are types defined in an upstream crate that have been // annotated as `#[non_exhaustive]`. use upstream::{Config, Error, Message}; // Cannot match on a non-exhaustive enum without including a wildcard arm. match error { Error::Message(ref s) => { }, Error::Other => { }, // would compile with: `_ => {},` } // Cannot match on a non-exhaustive struct without a wildcard. if let Ok(Config { window_width, window_height }) = config { // would compile with: `..` } match message { // Cannot match on a non-exhaustive struct enum variant without including a wildcard. Message::Send { from, to, contents } => { }, // Cannot match on a non-exhaustive tuple or unit enum variant. Message::Reaction(type) => { }, Message::Quit => { }, }
Non-exhaustive types are always considered inhabited in downstream crates.
© 2010 The Rust Project Developers
Licensed under the Apache License, Version 2.0 or the MIT license, at your option.
https://doc.rust-lang.org/reference/attributes/type_system.html