Error Handling #8
https://doc.rust-lang.org/book/error-handling.html
Reading from stdinの手前まででビルド通った。
extern crate getopts; extern crate rustc_serialize; extern crate csv; use getopts::Options; use std::env; use std::fs::File; use std::path::Path; use std::error::Error; // This struct represents the data in each row of the CSV file. // Type based decoding absolves us of a lot of the nitty gritty error // handling, like parsing strings as integers or floats. #[derive(Debug, RustcDecodable)] struct Row { country: String, city: String, accent_city: String, region: String, // Not every row has data for the population, latitude or longitude! // So we express them as `Option` types, which admits the possibility of // absence. The CSV parser will fill in the correct value for us. population: Option<u64>, latitude: Option<f64>, longitude: Option<f64>, } struct PopulationCount { city: String, country: String, // This is no longer an `Option` because values of this type are only // constructed if they have a population count. count: u64, } fn print_usage(program: &str, opts: Options) { println!("{}", opts.usage(&format!("Usage: {} [options] <data-path> <city>", program))); } fn search<P: AsRef<Path>> (file_path: P, city: &str) -> Result<Vec<PopulationCount>, Box<Error>> { let mut found = vec![]; let file = try!(File::open(file_path)); let mut rdr = csv::Reader::from_reader(file); for row in rdr.decode::<Row>() { let row = try!(row); match row.population { None => { } // Skip it. Some(count) => if row.city == city { found.push(PopulationCount { city: row.city, country: row.country, count: count, }); }, } } if found.is_empty() { Err(From::from("No matching cities with a population were found.")) } else { Ok(found) } } fn main() { let args: Vec<String> = env::args().collect(); let program = &args[0]; let mut opts = Options::new(); opts.optflag("h", "help", "Show this usage message."); let matches = match opts.parse(&args[1..]) { Ok(m) => { m } Err(e) => { panic!(e.to_string()) } }; if matches.opt_present("h") { print_usage(&program, opts); return; } let data_path = &matches.free[0]; let city: &str = &matches.free[1]; match search(data_path, city) { Ok(pops) => { for pop in pops { println!("{}, {}: {:?}", pop.city, pop.country, pop.count); } } Err(err) => println!("{}", err) } }
BLUE GIANT 10巻
コンビニにおいてあるのをみかけて、つい立ち読みしちゃいました。 セリフがないからこそ感じられる躍動感があります。 電子書籍化するあたりでちゃんと購入しよう。
- 作者: 石塚真一
- 出版社/メーカー: 小学館
- 発売日: 2017/03/10
- メディア: コミック
- この商品を含むブログ (2件) を見る
Error Handling #7
https://doc.rust-lang.org/book/error-handling.html
Error
というtrait
が存在する。
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