写点什么

Rust 中 non_exhaustive 的 enum

作者:胡译胡说
  • 2023-11-01
    北京
  • 本文字数:1480 字

    阅读完需:约 5 分钟

Rust中non_exhaustive的enum

所谓 non_exhaustive 的 enum 就是定义中带有#[non_exhaustive]enum,如


#[non_exhaustive]pub enum Error {    Message(String),    Other,}
复制代码


在定义了这个enum的 crate 中,non_exhaustive没有任何效果。


let error = Error::Other;// Non-exhaustive enums can be matched on exhaustively within the defining crate.match error {    Error::Message(ref s) => { },    Error::Other => { },}
复制代码


但若引用的 crate 中存在non_exhaustiveenum,会发生什么呢?


以 libpnet 这个 crate 为例,在https://docs.rs/pnet/latest/pnet/#这个页面给出的示例代码中,可以看到这么一段


// Create a new channel, dealing with layer 2 packetslet (mut tx, mut rx) = match datalink::channel(&interface, Default::default()) {    Ok(Ethernet(tx, rx)) => (tx, rx),    Ok(_) => panic!("Unhandled channel type"),    Err(e) => panic!("An error occurred when creating the datalink channel: {}", e)};
复制代码


datalink::channel()的返回值类型为Result<Channel, Error>,而Channel的类型是一个 enum,


pub enum Channel {    Ethernet(Box<dyn DataLinkSender, Global>, Box<dyn DataLinkReceiver, Global>),}
复制代码


如果datalink::channel()返回的是成功的结果(类型为Channel),将与第一个Ok(Ethernet(tx, rx))模式的前半部分匹配(因为Ok()就对应成功的结果)。而根据Channel的定义,Channel::Ethernet(tx, rx)是该enum唯一的成员(variant),所以只要是成功的结果,就应该匹配第 1 个模式,否则就匹配最后的Err(e)这个模式


这看起来满足 Rust 中的匹配必须是穷举式的(exhaustive)这一要求。因此似乎第 2 个模式Ok(_) => ,就显得多余了。但若去掉这行,编译时就会报错Ok(_) not covered


error[E0004]: non-exhaustive patterns: `Ok(_)` not covered  --> src/main.rs:33:31   |33 |     let (_tx, mut rx) = match datalink::channel(&interface, Default::default()) {   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `Ok(_)` not covered   |note: `Result<Channel, std::io::Error>` defined here...   |   = note: not covered   = note: the matched value is of type `Result<Channel, std::io::Error>`help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown   |38 ~         },39 +         Ok(_) => todo!()   |
For more information about this error, try `rustc --explain E0004`.
复制代码


这背后的原因就是因为enum Channelnon_exhaustive的,其完整定义是


// https://docs.rs/pnet_datalink/0.34.0/src/pnet_datalink/lib.rs.html#99/// A channel for sending and receiving at the data link layer.#[non_exhaustive]pub enum Channel {    /// A datalink channel which sends and receives Ethernet packets.    Ethernet(Box<dyn DataLinkSender>, Box<dyn DataLinkReceiver>),}
复制代码


而我们又在外部引用了包含这个enum的 crate。解决的办法就是加入Ok(_) => {...}


感觉这应该算 Rust 确保程序健壮性(鲁棒性)的一方面,在编译阶段就报出潜在的错误——咱也不知道引用的 crate 什么时候会在enum中增加新的成员。

参考

https://doc.rust-lang.org/beta/reference/attributes/type_system.html Type system attributes


https://docs.rs/pnet/latest/pnet/#examples This (fairly useless) code implements an Ethernet echo server.


发布于: 刚刚阅读数: 4
用户头像

胡译胡说

关注

还未添加个人签名 2019-08-27 加入

软件工程师、技术图书译者。译有《图解云计算架构》《图解量子计算机》《计算机是怎样跑起来的》《自制搜索引擎》等。

评论

发布
暂无评论
Rust中non_exhaustive的enum_rust_胡译胡说_InfoQ写作社区