类型系统属性
以下属性用于更改类型的使用方式。
non_exhaustive
属性
non_exhaustive
属性 表示类型或变体将来可能会添加更多的字段或变体。
可以应用于 [struct
] 、 [enum
] 和 enum
变体。
non_exhaustive
属性使用 元字 语法,因此不需要输入任何内容。
在定义的 crate 中,non_exhaustive
没有任何作用。
#![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, } // 非穷尽结构体可以在定义的 crate 中像普通结构体一样构造。 let config = Config { window_width: 640, window_height: 480 }; // 非穷尽结构体可以在定义的 crate 中进行完全匹配。 if let Config { window_width, window_height } = config { // ... } let error = Error::Other; let message = Message::Reaction(3); // 非穷尽枚举可以在定义的 crate 中进行完全匹配。 match error { Error::Message(ref s) => { }, Error::Other => { }, } match message { // 非穷尽变体可以在定义的 crate 中进行完全匹配。 Message::Send { from, to, contents } => { }, Message::Reaction(id) => { }, Message::Quit => { }, } }
在定义之外,使用 non_exhaustive
注解的类型有限制,以保持向后兼容性,当添加新字段或变量时。
不能在定义之外构造非穷尽类型:
- 不能使用 结构体表达式 (包括 函数更新语法) 构造非穷尽变体 (
struct
或enum
variant ) 。 - 可以构造 [
enum
] 实例。
// `Config`,`Error` 和 `Message` 是在上游 crate 中定义并使用了 `#[non_exhaustive]` 标记的类型。
use upstream::{Config, Error, Message};
// 无法构造 `Config` 的实例,如果在新版本中添加了新的字段,则会导致编译失败,因此不允许。
let config = Config { window_width: 640, window_height: 480 };
// 可以构造 `Error` 的实例,如果新的变量被引入,也不会导致编译失败。
let error = Error::Message("foo".to_string());
// 无法构造 `Message::Send` 或 `Message::Reaction` 的实例,如果在新版本中添加了新的字段,则会导致编译失败,因此不允许。
let message = Message::Send { from: 0, to: 1, contents: "foo".to_string(), };
let message = Message::Reaction(0);
// 无法构造 `Message::Quit` 的实例,如果将其转换为元组变量 `upstream`,则会导致编译失败。
let message = Message::Quit;
在定义类型的 crate 之外,在匹配非穷尽类型时存在以下限制:
- 当匹配非穷尽变体 (
struct
或enum
variant) 时,必须使用带有..
的 结构体模式 ,元组变体构造函数的可见性降为min($vis, pub(crate))
。 - 当匹配非穷尽
enum
时,匹配一个变体不会导致分支的穷尽性。
// `Config` , `Error` 和 `Message` 是在上游 crate 中定义的类型,已经被注解为 `#[non_exhaustive]`。
use upstream::{Config, Error, Message};
// 无法在非穷尽枚举上进行匹配,除非使用通配符。
match error {
Error::Message(ref s) => {},
Error::Other => {},
// 可以编译: `_ => {},`
}
// 无法在非穷尽的结构体上进行匹配,除非使用通配符。
if let Ok(Config { window_width, window_height }) = config {
// 可以编译: `..`
}
match message {
// 无法在非穷尽的结构体上进行匹配,除非使用通配符。
Message::Send { from, to, contents } => { },
// 无法匹配非穷尽的元组或单元枚举变体。
Message::Reaction(type) => { },
Message::Quit => { },
}
在外部的 crate 中,也不允许将非穷尽类型进行强制类型转换。
use othercrate::NonExhaustiveEnum;
// 无法在其定义 crate 之外将非穷尽枚举转换为其他类型。
let _ = NonExhaustiveEnum::default() as u8;
非穷尽类型在下游的 crate 中总是被视为是有 inhabitant(指代值或实例) 。