类型系统属性

以下属性用于更改类型的使用方式。

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 注解的类型有限制,以保持向后兼容性,当添加新字段或变量时。

不能在定义之外构造非穷尽类型:

// `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 之外,在匹配非穷尽类型时存在以下限制:

  • 当匹配非穷尽变体 (structenum 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(指代值或实例) 。