ErrorKind :: __ Nonexhaustive的目的是什么?

tan*_*umo 13 rust

std::io::ErrorKind有变种__Nonexhaustive.如果这个变体不存在,我不知道是什么问题.

这个变种的目的是什么?

huo*_*uon 18

它旨在ErrorKind通过强制match使用稳定代码中的任何语句来实现全面的扩展,从而允许将来扩展枚举_.

具体来说,变量标记为不稳定,因此不能在稳定通道上引用,因此编译器会拒绝代码

fn foo(x: Error) {
    match x.kind() {
        ErrorKind::NotFound => {}
        ErrorKind::PermissionDenied => {}
        ErrorKind::ConnectionRefused => {}
        ErrorKind::ConnectionReset => {}
        ErrorKind::ConnectionAborted => {}
        ErrorKind::NotConnected => {}
        ErrorKind::AddrInUse => {}
        ErrorKind::AddrNotAvailable => {}
        ErrorKind::BrokenPipe => {}
        ErrorKind::AlreadyExists => {}
        ErrorKind::WouldBlock => {}
        ErrorKind::InvalidInput => {}
        ErrorKind::InvalidData => {}
        ErrorKind::TimedOut => {}
        ErrorKind::WriteZero => {}
        ErrorKind::Interrupted => {}
        ErrorKind::Other => {}
        ErrorKind::UnexpectedEof => {}
        ErrorKind::UnexpectedEOF => {}
        ErrorKind::__Nonexhaustive => {}
    }
}
Run Code Online (Sandbox Code Playgroud)
<anon>:24:9: 24:35 error: use of unstable library feature 'io_error_internals': better expressed through extensible enums that this enum cannot be exhaustively matched against (see issue #0)
<anon>:24         ErrorKind::__Nonexhaustive => {}
                  ^~~~~~~~~~~~~~~~~~~~~~~~~~
Run Code Online (Sandbox Code Playgroud)

如果此代码在稳定的Rust上成功编译,那么ErrorKind在将来的版本中添加一个变体会破坏任何match类似上面的代码,并且破坏稳定的代码是不好的.代码中断因为Rust中的匹配必须是详尽的,也就是说,它们必须以某种方式涵盖所有可能性,因此添加变量意味着不包括可能性.

相反,程序员必须写:

fn foo(x: Error) {
    match x.kind() {
        ErrorKind::NotFound => {}
        ErrorKind::PermissionDenied => {}
        ErrorKind::ConnectionRefused => {}
        ErrorKind::ConnectionReset => {}
        ErrorKind::ConnectionAborted => {}
        ErrorKind::NotConnected => {}
        ErrorKind::AddrInUse => {}
        ErrorKind::AddrNotAvailable => {}
        ErrorKind::BrokenPipe => {}
        ErrorKind::AlreadyExists => {}
        ErrorKind::WouldBlock => {}
        ErrorKind::InvalidInput => {}
        ErrorKind::InvalidData => {}
        ErrorKind::TimedOut => {}
        ErrorKind::WriteZero => {}
        ErrorKind::Interrupted => {}
        ErrorKind::Other => {}
        ErrorKind::UnexpectedEof => {}
        ErrorKind::UnexpectedEOF => {}
        _ => {}
    }
}
Run Code Online (Sandbox Code Playgroud)

这意味着ErrorKind将来添加的任何变体(例如,新IO功能的新错误可能性)将落在_手臂下,因此现有的稳定代码不会中断.


Fra*_*gné 6

这个隐藏变体的目的是阻止你写这样的东西(因为存在而不能精确编译__Nonexhaustive):

use std::io::ErrorKind;

fn main() {
    let error_kind: ErrorKind = unimplemented!();
    match error_kind {
        ErrorKind::NotFound => unimplemented!(),
        ErrorKind::PermissionDenied => unimplemented!(),
        ErrorKind::ConnectionRefused => unimplemented!(),
        ErrorKind::ConnectionReset => unimplemented!(),
        ErrorKind::ConnectionAborted => unimplemented!(),
        ErrorKind::NotConnected => unimplemented!(),
        ErrorKind::AddrInUse => unimplemented!(),
        ErrorKind::AddrNotAvailable => unimplemented!(),
        ErrorKind::BrokenPipe => unimplemented!(),
        ErrorKind::AlreadyExists => unimplemented!(),
        ErrorKind::WouldBlock => unimplemented!(),
        ErrorKind::InvalidInput => unimplemented!(),
        ErrorKind::InvalidData => unimplemented!(),
        ErrorKind::TimedOut => unimplemented!(),
        ErrorKind::WriteZero => unimplemented!(),
        ErrorKind::Interrupted => unimplemented!(),
        ErrorKind::Other => unimplemented!(),
        ErrorKind::UnexpectedEOF => unimplemented!(),
        ErrorKind::UnexpectedEof => unimplemented!(),
        // note: no wildcard match arm here
    };
}
Run Code Online (Sandbox Code Playgroud)

究其原因,为什么标准库的开发者不希望你这样做是为了保留变种增加的能力ErrorKind的未来.该__Nonexhaustive变体可以通过简单地处理每个变体来阻止您进行详尽的匹配; 你必须有一个通配符臂才能进行详尽的匹配.

在Rust中,match表达式要求匹配的表达式的所有可能模式都具有相应的arm,以便match表达式始终具有明确定义的显式值.match涵盖所有模式的A 称为穷举匹配.使用enums,Rust让我们只列出所有变体.例如,对于Option,其中只有2个变种,命名为NoneSome,我们可以这样写:

fn main() {
    let option: Option<()> = unimplemented!();
    match option {
        None => unimplemented!(),
        Some(()) => unimplemented!(),
    };
}
Run Code Online (Sandbox Code Playgroud)

match编译好,因为它涵盖了所有可能的模式进行option.但是,如果Option类型获得了另一个变体,那么突然你的代码将不再编译,因为它将不再是详尽无遗的.当然,这没有意义Option,所以这种Option类型不会发挥"非穷尽"游戏.但如果__Nonexhaustive不存在,添加一个变体ErrorKind将是一个突破性的变化; 任何完全匹配(没有通配符)的代码ErrorKind都会突然停止编译.此代码可能位于您的应用程序所依赖的包中,并且该破坏可能会阻止您升级Rust,直到包修复为止!