Rust中non_exhaustive的enum使用確保程序健壯性
Rust中non_exhaustive的enum
所謂non_exhaustive的enum就是定義中帶有#[non_exhaustive]
的enum
,如
#[non_exhaustive] pub enum Error { Message(String), Other, }
在定義了這個(gè)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_exhaustive
的enum
,會(huì)發(fā)生什么呢?
以libpnet這個(gè)crate為例
在https://docs.rs/pnet/latest/pnet/#這個(gè)頁面給出的示例代碼中,可以看到這么一段
// Create a new channel, dealing with layer 2 packets let (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
的類型是一個(gè)enum,
pub enum Channel { Ethernet(Box<dyn DataLinkSender, Global>, Box<dyn DataLinkReceiver, Global>), }
atalink::channel()返回結(jié)果分析
如果datalink::channel()
返回的是成功的結(jié)果(類型為Channel
),將與第一個(gè)Ok(Ethernet(tx, rx))
模式的前半部分匹配(因?yàn)?code>Ok()就對(duì)應(yīng)成功的結(jié)果)。
而根據(jù)Channel
的定義,Channel::Ethernet(tx, rx)
是該enum
唯一的成員(variant),所以只要是成功的結(jié)果,就應(yīng)該匹配第1個(gè)模式,否則就匹配最后的Err(e)
這個(gè)模式。
這看起來滿足Rust中的匹配必須是窮舉式的(exhaustive)這一要求。因此似乎第2個(gè)模式Ok(_) => ,
就顯得多余了。但若去掉這行,編譯時(shí)就會(huì)報(bào)錯(cuò)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`.
這背后的原因就是因?yàn)?code>enum Channel是non_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>), }
而我們又在外部引用了包含這個(gè)enum
的crate。解決的辦法就是加入Ok(_) => {...}
。
感覺這應(yīng)該算Rust確保程序健壯性(魯棒性)的一方面,在編譯階段就報(bào)出潛在的錯(cuò)誤——咱也不知道引用的crate什么時(shí)候會(huì)在enum
中增加新的成員。
參考
https://doc.rust-lang.org/beta/reference/attributes/type_syst... Type system attributes
https://docs.rs/pnet/latest/pnet/#examples This (fairly useless) code implements an Ethernet echo server.
以上就是Rust中non_exhaustive的enum使用確保程序健壯性的詳細(xì)內(nèi)容,更多關(guān)于Rust 的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章

Rust錯(cuò)誤處理之`foo(...)?`的用法與錯(cuò)誤類型轉(zhuǎn)換小結(jié)

Rust?use關(guān)鍵字妙用及模塊內(nèi)容拆分方法

Rust重載運(yùn)算符之復(fù)數(shù)四則運(yùn)算的實(shí)現(xiàn)

Rust 的 into_owned() 方法實(shí)例詳解