Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I match on a specific io::Error type?

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

use byteorder::{BigEndian, ReadBytesExt}; // 1.3.4
use std::fs::File;

fn main() {
    let filename = "/etc/hosts";
    let mut file = File::open(filename).expect("Cannot open file");
    loop {
        let binary = match file.read_u16::<BigEndian>() {
            Ok(binary) => binary,
            Err(e) => panic!("Can't read from file: {}, err {}", filename, e),
            // Can I catch the EOF error here?
        };
        println!("{:?}", binary);
    }
}
like image 809
user145632 Avatar asked Feb 13 '15 02:02

user145632


3 Answers

This works in Rust version 1.17.0 (and probably back to Rust 1.0):

let binary = match file.read_u16::<BigEndian>() {
    Err(ref e) if e.kind() == std::io::ErrorKind::UnexpectedEof => break,
    Err(e) => panic!("Can't read from file: {}, err {}", filename, e),
    Ok(binary) => binary,
};
like image 64
sarnold Avatar answered Oct 19 '22 23:10

sarnold


Editor's note: This code example is from a version of Rust prior to 1.0 and does not apply to stable Rust 1.0 io::Error. The concept of nested pattern matching still applies in other contexts.

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”.

like image 8
Chris Morgan Avatar answered Oct 19 '22 23:10

Chris Morgan


I find...

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),

(I'm not sure what other errors we could expect to get...)

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.

This works as of Rust 1.25.

like image 8
kevlarr Avatar answered Oct 19 '22 22:10

kevlarr