user145632
user145632

Reputation: 551

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);
    }
}

Upvotes: 44

Views: 22133

Answers (5)

kevlarr
kevlarr

Reputation: 1162

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.

Upvotes: 15

sarnold
sarnold

Reputation: 104120

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,
};

Upvotes: 31

Chris Morgan
Chris Morgan

Reputation: 90912

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

Upvotes: 8

nbari
nbari

Reputation: 27005

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;
    }
}

Upvotes: 2

user145632
user145632

Reputation: 551

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

Upvotes: 0

Related Questions