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 }

Concurrency #2

https://doc.rust-lang.org/book/concurrency.html

並行処理続き。channelについて。rxからtxにデータが渡るまで、tx側は処理を待つ。

use std::thread;
use std::sync::mpsc;

fn main() {
    let (tx, rx) = mpsc::channel();

    for i in 0..10 {
        let tx = tx.clone();

        thread::spawn(move || {
            let answer = i * i;

            tx.send(answer).unwrap();
        });
    }

    for _ in 0..10 {
        println!("{}", rx.recv().unwrap());
    }

    let handle = thread::spawn(move || {
        panic!("oops!");
    });
    let result = handle.join();
    assert!(result.is_err());
}
$ cargo run
    Finished debug [unoptimized + debuginfo] target(s) in 0.0 secs
     Running `target/debug/5_6_concurrency`
0
1
4
16
25
9
64
36
81
49
thread '<unnamed>' panicked at 'oops!', src/main.rs:22
note: Run with `RUST_BACKTRACE=1` for a backtrace.

Concurrency

https://doc.rust-lang.org/book/concurrency.html

並列処理について。

use std::sync::{Arc, Mutex};
use std::thread;
use std::time::Duration;

fn main() {
    let data = Arc::new(Mutex::new(vec![1, 2, 3]));

    for i in 0..3 {
        let data = data.clone();

        thread::spawn(move || {
            let mut data = data.lock().unwrap();
            data[0] += i;
        });
    }

    thread::sleep(Duration::from_millis(50));

    println!("{:?}", data);
}
$ cargo run
    Finished debug [unoptimized + debuginfo] target(s) in 0.0 secs
     Running `target/debug/5_6_concurrency`
Mutex { data: [4, 2, 3] }

Iterators

https://doc.rust-lang.org/book/iterators.html

fn main() {
    let num = (1..)
        .filter(|&x| x % 2 == 0)
        .filter(|&x| x % 3 == 0)
        .take(5)
        .collect::<Vec<i32>>();

    for n in num.iter() {
       println!("{}", n);
    }
}
$ cargo run
    Finished debug [unoptimized + debuginfo] target(s) in 1.21 secs
     Running `target/debug/5_5_iterators`
6
12
18
24
30

関数型プログラミングでこういうの見かけますが、メソッド呼び出しを連結できるのは良いですね。