mirror of https://github.com/rust-lang/reference
Document how `non_exhaustive` interacts with tuple and unit-like structs.
This commit is contained in:
parent
55694913b1
commit
ec0065fd92
|
@ -20,6 +20,12 @@ pub struct Config {
|
||||||
pub window_height: u16,
|
pub window_height: u16,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[non_exhaustive]
|
||||||
|
pub struct Token;
|
||||||
|
|
||||||
|
#[non_exhaustive]
|
||||||
|
pub struct Id(pub u64);
|
||||||
|
|
||||||
#[non_exhaustive]
|
#[non_exhaustive]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
Message(String),
|
Message(String),
|
||||||
|
@ -34,11 +40,13 @@ pub enum Message {
|
||||||
|
|
||||||
// Non-exhaustive structs can be constructed as normal within the defining crate.
|
// Non-exhaustive structs can be constructed as normal within the defining crate.
|
||||||
let config = Config { window_width: 640, window_height: 480 };
|
let config = Config { window_width: 640, window_height: 480 };
|
||||||
|
let token = Token;
|
||||||
|
let id = Id(4);
|
||||||
|
|
||||||
// Non-exhaustive structs can be matched on exhaustively within the defining crate.
|
// Non-exhaustive structs can be matched on exhaustively within the defining crate.
|
||||||
if let Config { window_width, window_height } = config {
|
let Config { window_width, window_height } = config;
|
||||||
// ...
|
let Token = token;
|
||||||
}
|
let Id(id_number) = id;
|
||||||
|
|
||||||
let error = Error::Other;
|
let error = Error::Other;
|
||||||
let message = Message::Reaction(3);
|
let message = Message::Reaction(3);
|
||||||
|
@ -64,30 +72,47 @@ Non-exhaustive types cannot be constructed outside of the defining crate:
|
||||||
|
|
||||||
- Non-exhaustive variants ([`struct`][struct] or [`enum` variant][enum]) cannot be constructed
|
- Non-exhaustive variants ([`struct`][struct] or [`enum` variant][enum]) cannot be constructed
|
||||||
with a [_StructExpression_] \(including with [functional update syntax]).
|
with a [_StructExpression_] \(including with [functional update syntax]).
|
||||||
|
- The visibility of the same-named constant of a [unit-like struct][struct]
|
||||||
|
is lowered to `min($vis, pub(crate))`.
|
||||||
|
- The visibility of the same-named constructor function of a [tuple struct][struct]
|
||||||
|
is lowered to `min($vis, pub(crate))`.
|
||||||
- [`enum`][enum] instances can be constructed.
|
- [`enum`][enum] instances can be constructed.
|
||||||
|
|
||||||
|
The following examples of construction do not compile when outside the defining crate:
|
||||||
|
|
||||||
<!-- ignore: requires external crates -->
|
<!-- ignore: requires external crates -->
|
||||||
```rust,ignore
|
```rust,ignore
|
||||||
// `Config`, `Error`, and `Message` are types defined in an upstream crate that have been
|
// These are types defined in an upstream crate that have been annotated as
|
||||||
// annotated as `#[non_exhaustive]`.
|
// `#[non_exhaustive]`.
|
||||||
use upstream::{Config, Error, Message};
|
use upstream::{Config, Token, Id, Error, Message};
|
||||||
|
|
||||||
// Cannot construct an instance of `Config`, if new fields were added in
|
// 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
|
// a new version of `upstream` then this would fail to compile, so it is
|
||||||
// disallowed.
|
// disallowed.
|
||||||
let config = Config { window_width: 640, window_height: 480 };
|
let config = Config { window_width: 640, window_height: 480 };
|
||||||
|
|
||||||
// Can construct an instance of `Error`, new variants being introduced would
|
// Cannot construct an instance of `Token`; if new fields were added, then
|
||||||
|
// it would not be a unit-like struct any more, so the same-named constant
|
||||||
|
// created by it being a unit-like struct is not public outside the crate;
|
||||||
|
// this code fails to compile.
|
||||||
|
let token = Token;
|
||||||
|
|
||||||
|
// Cannot construct an instance of `Id`; if new fields were added, then
|
||||||
|
// its constructor function signature would change, so its constructor
|
||||||
|
// function is not public outside the crate; this code fails to compile.
|
||||||
|
let id = Id(5);
|
||||||
|
|
||||||
|
// Can construct an instance of `Error`; new variants being introduced would
|
||||||
// not result in this failing to compile.
|
// not result in this failing to compile.
|
||||||
let error = Error::Message("foo".to_string());
|
let error = Error::Message("foo".to_string());
|
||||||
|
|
||||||
// Cannot construct an instance of `Message::Send` or `Message::Reaction`,
|
// Cannot construct an instance of `Message::Send` or `Message::Reaction`;
|
||||||
// if new fields were added in a new version of `upstream` then this would
|
// if new fields were added in a new version of `upstream` then this would
|
||||||
// fail to compile, so it is disallowed.
|
// fail to compile, so it is disallowed.
|
||||||
let message = Message::Send { from: 0, to: 1, contents: "foo".to_string(), };
|
let message = Message::Send { from: 0, to: 1, contents: "foo".to_string(), };
|
||||||
let message = Message::Reaction(0);
|
let message = Message::Reaction(0);
|
||||||
|
|
||||||
// Cannot construct an instance of `Message::Quit`, if this were converted to
|
// Cannot construct an instance of `Message::Quit`; if this were converted to
|
||||||
// a tuple-variant `upstream` then this would fail to compile.
|
// a tuple-variant `upstream` then this would fail to compile.
|
||||||
let message = Message::Quit;
|
let message = Message::Quit;
|
||||||
```
|
```
|
||||||
|
@ -100,11 +125,13 @@ There are limitations when matching on non-exhaustive types outside of the defin
|
||||||
- When pattern matching on a non-exhaustive [`enum`][enum], matching on a variant does not
|
- When pattern matching on a non-exhaustive [`enum`][enum], matching on a variant does not
|
||||||
contribute towards the exhaustiveness of the arms.
|
contribute towards the exhaustiveness of the arms.
|
||||||
|
|
||||||
|
The following examples of matching do not compile when outside the defining crate:
|
||||||
|
|
||||||
<!-- ignore: requires external crates -->
|
<!-- ignore: requires external crates -->
|
||||||
```rust, ignore
|
```rust, ignore
|
||||||
// `Config`, `Error`, and `Message` are types defined in an upstream crate that have been
|
// These are types defined in an upstream crate that have been annotated as
|
||||||
// annotated as `#[non_exhaustive]`.
|
// `#[non_exhaustive]`.
|
||||||
use upstream::{Config, Error, Message};
|
use upstream::{Config, Token, Id, Error, Message};
|
||||||
|
|
||||||
// Cannot match on a non-exhaustive enum without including a wildcard arm.
|
// Cannot match on a non-exhaustive enum without including a wildcard arm.
|
||||||
match error {
|
match error {
|
||||||
|
@ -118,6 +145,13 @@ if let Ok(Config { window_width, window_height }) = config {
|
||||||
// would compile with: `..`
|
// would compile with: `..`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Cannot match a non-exhaustive unit-like or tuple struct except by using
|
||||||
|
// braced struct syntax with a wildcard.
|
||||||
|
// This would compile as `let Token { .. } = token;`
|
||||||
|
let Token = token;
|
||||||
|
// This would compile as `let Id { 0: id_number, .. } = id;`
|
||||||
|
let Id(id_number) = id;
|
||||||
|
|
||||||
match message {
|
match message {
|
||||||
// Cannot match on a non-exhaustive struct enum variant without including a wildcard.
|
// Cannot match on a non-exhaustive struct enum variant without including a wildcard.
|
||||||
Message::Send { from, to, contents } => { },
|
Message::Send { from, to, contents } => { },
|
||||||
|
|
Loading…
Reference in New Issue