Matching on a specific error type

2019-06-15 15:49发布

问题:

I am trying to read in a file until the end 2 bytes at a time. I want to catch the EOF error. I have this code:

loop {
    let binary = match file.read_be_u16() {
        Ok(binary) => binary,
        Err(e) => panic!("Can't read from file: {}, err {}", filename, e),
                  // Can I catch this EOF error here?
    };
    println!("{:?}", binary);
}

回答1:

At least rustc version rustc 1.17.0 (56124baa9 2017-04-24) doesn't allow destructuring the Err that Chris Morgan's answer used. I found this to work:

Err(ref e) if e.kind() == std::io::ErrorKind::NotFound => true,
Err(e) => { println!("{:?}", e); false }
Ok(_) => false,


回答2:

You can match the kind as part of the pattern, using some more advanced features of pattern matching:

Err(IoError { kind: IoErrorKind::EndOfFile, .. }) => break,
Err(e) => panic!("Can't read from file: {}, err {}", filename, e),

The first variant means “an Err containing an IoError where kind is IoErrorKind::EndOfFile and all the other fields are whatever you like”. The second then means “any other Err, binding the contained value to the variable name e”.



回答3:

Being new to Rust I'm not really too aware of the "Rusty" way to do things (so not sure if this would be discouraged) but I personally find...

Ok(binary) => binary,
Err(e) => match e.kind() {
    EndOfFile => break,
    [..SomeOtherError..] => do_something(),
    _ => panic!("Can't read from file: {}, err {}", filename, e),
},

... to be more readable than...

Ok(binary) => binary,
Err(ref e) if e.kind() == EndOfFile => break,
Err(ref e) if e.kind() == [..SomeOtherError..] => do_something(),
Err(e) => panic!("Can't read from file: {}, err {}", filename, e),

(Not sure what other errors we could expect to get...)

Obviously, in other situations where the match guards might not be the same - the way that we're repeating e.kind() - we couldn't use the nested match


Note: Works as of rustc 1.25.0 (84203cac6 2018-03-25)



回答4:

I figured it out. I changed this line to check the error type! Hope this helps others.

Err(e) => if e.kind == IoErrorKind::EndOfFile { break } else { panic!("Can't read from file: {}, err {}", filename, e) },


回答5:

Here is an example of matching a MySQL IoError:

match pool.prep_exec("SELECT SLEEP(10)", ()) {
    Ok(_) => (),
    Err(mysql::Error::IoError(e)) => {
        eprintln!("IoError: {}", e);
        do_something();
    }
    Err(e) => {
        eprintln!("{}", e);
        return;
    }
}