Error Handling #6

https://doc.rust-lang.org/book/error-handling.html

エラーの定義。

use std::io;
use std::num;

// We derive `Debug` because all types should probably derive `Debug`.
// This gives us a reasonable human readable description of `CliError` values.
#[derive(Debug)]
enum CliError {
    Io(io::Error),
    Parse(num::ParseIntError),
}

use std::fs::File;
use std::io::Read;
use std::path::Path;

fn file_double<P: AsRef<Path>>(file_path: P) -> Result<i32, CliError> {
    let mut file = try!(File::open(file_path).map_err(CliError::Io));
    let mut contents = String::new();
    try!(file.read_to_string(&mut contents).map_err(CliError::Io));
    let n: i32 = try!(contents.trim().parse().map_err(CliError::Parse));
    Ok(2 * n)
}

fn main() {
    match file_double("foobar") {
        Ok(n) => println!("{}", n),
        Err(err) => println!("Error: {:?}", err),
    }
}
$ cargo run
    Finished debug [unoptimized + debuginfo] target(s) in 0.0 secs
     Running `target/debug/5_7_error_handling`
Error: Io(Error { repr: Os { code: 2, message: "No such file or directory" } })
$ touch foobar
$ cargo run
    Finished debug [unoptimized + debuginfo] target(s) in 0.0 secs
     Running `target/debug/5_7_error_handling`
Error: Parse(ParseIntError { kind: Empty })
$ echo 3 > foobar
$ cargo run
    Finished debug [unoptimized + debuginfo] target(s) in 0.0 secs
     Running `target/debug/5_7_error_handling`
6
$ echo "a" > foobar
$ cargo run
    Finished debug [unoptimized + debuginfo] target(s) in 0.0 secs
     Running `target/debug/5_7_error_handling`
Error: Parse(ParseIntError { kind: InvalidDigit })

Error Handling #5

https://doc.rust-lang.org/book/error-handling.html

ファイル処理の異常処理の続き。エラーの時の処理が明示的になってきたように思う。

use std::fs::File;
use std::io::Read;
use std::path::Path;

fn file_double<P: AsRef<Path>>(file_path: P) -> Result<i32, String> {
    let mut file = match File::open(file_path) {
        Ok(file) => file,
        Err(err) => return Err(err.to_string()),
    };
    let mut contents = String::new();
    if let Err(err) = file.read_to_string(&mut contents) {
        return Err(err.to_string());
    }
    let n: i32 = match contents.trim().parse() {
        Ok(n) => n,
        Err(err) => return Err(err.to_string()),
    };
    Ok(2 * n)
}

fn main() {
    match file_double("foobar") {
        Ok(n) => println!("{}", n),
        Err(err) => println!("Error: {}", err),
    }
}

Error Handling #4

https://doc.rust-lang.org/book/error-handling.html

use std::fs::File;
use std::io::Read;
use std::path::Path;

fn file_double<P: AsRef<Path>>(file_path: P) -> i32 {
    let mut file = File::open(file_path).unwrap(); // error 1
    let mut contents = String::new();
    file.read_to_string(&mut contents).unwrap(); // error 2
    let n: i32 = contents.trim().parse().unwrap(); // error 3
    2 * n
}

fn main() {
    let doubled = file_double("foobar");
    println!("{}", doubled);
}
$ cargo run
   Compiling 5_7_error_handling v0.1.0 (file:///Users/miura/work/git-work/exercises/The_Rust_Programming_Language/5_7_error_handling)
    Finished debug [unoptimized + debuginfo] target(s) in 1.38 secs
     Running `target/debug/5_7_error_handling`
thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: Error { repr: Os { code: 2, message: "No such file or directory" } }', ../src/libcore/result.rs:837
note: Run with `RUST_BACKTRACE=1` for a backtrace.
$ touch foobar
$ cargo run
    Finished debug [unoptimized + debuginfo] target(s) in 0.0 secs
     Running `target/debug/5_7_error_handling`
thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: ParseIntError { kind: Empty }', ../src/libcore/result.rs:837
note: Run with `RUST_BACKTRACE=1` for a backtrace.
$ echo 1 > foobar
(anaconda3-4.2.0) miura (master *) 5_7_error_handling $ cargo run
    Finished debug [unoptimized + debuginfo] target(s) in 0.0 secs
     Running `target/debug/5_7_error_handling`
2

Error Handling #3

https://doc.rust-lang.org/book/error-handling.html

use std::env;すると、argv.nthで引数をとれる。 引数の有無でエラー判定するための方法。

use std::env;

fn ok_or<T, E>(option: Option<T>, err: E) -> Result<T, E> {
    match option {
        Some(val) => Ok(val),
        None => Err(err),
    }
}

fn double_arg(mut argv: env::Args) -> Result<i32, String> {
    argv.nth(1)
        .ok_or("Please give at least one argument".to_owned())
        .and_then(|arg| arg.parse::<i32>().map_err(|err| err.to_string()))
        .map(|n| 2 * n)
}

fn main() {
    match double_arg(env::args()) {
        Ok(n) => println!("{}", n),
        Err(err) => println!("Error: {}", err),
    }
}
$ cargo run
    Finished debug [unoptimized + debuginfo] target(s) in 0.0 secs
     Running `target/debug/5_7_error_handling`
Error: Please give at least one argument
$ cargo run a
    Finished debug [unoptimized + debuginfo] target(s) in 0.0 secs
     Running `target/debug/5_7_error_handling a`
Error: invalid digit found in string
$ cargo run 3
    Finished debug [unoptimized + debuginfo] target(s) in 0.0 secs
     Running `target/debug/5_7_error_handling 3`
6

Error Handling #2

https://doc.rust-lang.org/book/error-handling.html

文字列を整数にパースするときのエラーハンドリング。

use std::num::ParseIntError;

fn double_number(number_str: &str) -> Result<i32, ParseIntError> {
    number_str.parse::<i32>().map(|n| 2 * n)
}

fn main() {
    match double_number("10") {
        Ok(n) => assert_eq!(n, 20),
        Err(err) => println!("Error: {:?}", err),
    }
    match double_number("a") {
        Ok(n) => assert_eq!(n, 20),
        Err(err) => println!("Error: {:?}", err),
    }
}
$ cargo run
    Finished debug [unoptimized + debuginfo] target(s) in 0.0 secs
     Running `target/debug/5_7_error_handling`
Error: ParseIntError { kind: InvalidDigit }