#TheBook #Rust https://doc.rust-jp.rs/book-ja/ch12-00-an-io-project.html ## コマンドライン引数を受け付ける - [[std.env.args]]と[[std.env.args_os]] ## リファクタリングしてモジュール性とエラー処理を向上させる - バイナリプロジェクトのガイドライン - プログラムを`main.rs`と`lib.rs`に分けて、ロジックを`lib.rs`に移動する - コマンドライン引数の解析ロジックも`lib.rs`におく - ただし、シンプルな場合は`main.rs`でもよい > [!question]- コンストラクタとnewの使い分けは? > 今回のケースだと`new`が冗長に感じるのだけど、何か基準があるのだろうか? [[let-else]]を使うと以下のような感じ。エラーメッセージが取得できないので、[[Result]]で使うことはあまりなさそう。 ```rust let Ok(config) = Config::new(&args) else { println!("Problem parsing arguments:"); process::exit(1); }; ``` `main.rs` ```rust use minigrep::{run, Config}; use std::env; use std::process; fn main() { let args: Vec<String> = env::args().collect(); let config = Config::new(&args).unwrap_or_else(|err| { println!("Problem parsing arguments: {}", err); process::exit(1); }); if let Err(e) = run(config) { println!("Application error: {}", e); process::exit(1); } } ``` `lib.rs` ```rust use std::error::Error; use std::fs::File; use std::io::Read; pub fn run(config: Config) -> Result<(), Box<dyn Error>> { let mut f = File::open(config.filename)?; let mut contents = String::new(); f.read_to_string(&mut contents)?; println!("contents = {}", contents); Ok(()) } pub struct Config { query: String, filename: String, } impl Config { pub fn new(args: &[String]) -> Result<Config, &'static str> { if args.len() < 3 { return Err("not enough arguments"); } let query = args[1].clone(); let filename = args[2].clone(); Ok(Config { query, filename }) } } ``` ## 標準出力ではなく標準エラーにエラーメッセージを書き込む - [[eprintlnマクロ]]ってエラー出力の`e`だったのね...