Error Handling #10
https://doc.rust-lang.org/book/error-handling.html
サンプルの'‘city-pop’‘を最後まで。
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; use std::io; use std::process; #[derive(Debug)] enum CliError { Io(io::Error), Csv(csv::Error), NotFound, } use std::fmt; impl fmt::Display for CliError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { CliError::Io(ref err) => err.fmt(f), CliError::Csv(ref err) => err.fmt(f), CliError::NotFound => write!(f, "No matching cities with a \ population were found."), } } } impl Error for CliError { fn description(&self) -> &str { match *self { CliError::Io(ref err) => err.description(), CliError::Csv(ref err) => err.description(), CliError::NotFound => "not found", } } fn cause(&self) -> Option<&Error> { match *self { CliError::Io(ref err) => Some(err), CliError::Csv(ref err) => Some(err), // Our custom error doesn't have an underlying cause, // but we could modify it so that it does. CliError::NotFound => None, } } } impl From<io::Error> for CliError { fn from(err: io::Error) -> CliError { CliError::Io(err) } } impl From<csv::Error> for CliError { fn from(err: csv::Error) -> CliError { CliError::Csv(err) } } // 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] <city>", program))); } fn search<P: AsRef<Path>> (file_path: &Option<P>, city: &str) -> Result<Vec<PopulationCount>, CliError> { let mut found = vec![]; let input: Box<io::Read> = match *file_path { None => Box::new(io::stdin()), Some(ref file_path) => Box::new(try!(File::open(file_path))), }; let mut rdr = csv::Reader::from_reader(input); 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(CliError::NotFound) } else { Ok(found) } } fn main() { let args: Vec<String> = env::args().collect(); let program = &args[0]; let mut opts = Options::new(); opts.optopt("f", "file", "Choose an input file, instead of using STDIN.", "NAME"); opts.optflag("h", "help", "Show this usage message."); opts.optflag("q", "quiet", "Silences errors and warnings."); // ... 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.opt_str("f"); let city = if !matches.free.is_empty() { &matches.free[0] } else { print_usage(&program, opts); return; }; match search(&data_path, city) { Err(CliError::NotFound) if matches.opt_present("q") => process::exit(1), Err(err) => panic!("{}", err), Ok(pops) => for pop in pops { println!("{}, {}: {:?}", pop.city, pop.country, pop.count); } } }
Error Handling #9
https://doc.rust-lang.org/book/error-handling.html
今日は、Error handling with a custom typeの手前まで。
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), } }