【Rust】がばがばRust独学 - 12. I/O Project
Rustの公式ドキュメントを通して、Rustを独学していく記事になります。(がば要素あり)
今回は、I/Oについて学びつつ、気になった点をコード確認した結果を記事にしています。
- versions
$ rustc --version rustc 1.40.0 (73528e339 2019-12-16)
- Accepting Command Line Arguments
- Reading a File
- Refactoring to Improve Modularity and Error Handling
- Developing the Library’s Functionality with Test-Driven Development
- Working with Environment Variables
- Writing Error Messages to Standard Error Instead of Standard Output
- まとめ
- 最後に
Accepting Command Line Arguments
An I/O Project: Building a Command Line Program - The Rust Programming Language
引数読み取り
env::args().collect()
により、引数の読み取りを実施できます。
use std::env; fn main() { let args: Vec<String> = env::args().collect(); println!("{:?}", args); }
bash-3.2$ cargo run Finished dev [unoptimized + debuginfo] target(s) in 0.04s Running `target/debug/minigrep` ["target/debug/minigrep"] bash-3.2$ cargo run needle haystack Finished dev [unoptimized + debuginfo] target(s) in 0.00s Running `target/debug/minigrep needle haystack` ["target/debug/minigrep", "needle", "haystack"]
引数の格納
&args[x]
により引数を格納することが可能です。
use std::env; fn main() { let args: Vec<String> = env::args().collect(); println!("{:?}", args); let query = &args[1]; let filename = &args[2]; println!("Searching for {}", query); println!("In file {}", filename); }
$ cargo run searchstring example-filename.txt ["target/debug/minigrep", "searchstring", "example-filename.txt"] Searching for searchstring In file example-filename.txt
もちろん、直でindexを指定しているため、引数が足りていない場合はpanicを引き起こします。
bash-3.2$ cargo run Compiling minigrep v0.1.0 (/Users/k-hara/Work/training-rust/minigrep) Finished dev [unoptimized + debuginfo] target(s) in 0.29s Running `target/debug/minigrep` ["target/debug/minigrep"] thread 'main' panicked at 'index out of bounds: the len is 1 but the index is 1', /rustc/73528e339aae0f17a15ffa49a8ac608f50c6cf14/src/libcore/slice/mod.rs:2796:10 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace.
Reading a File
Reading a File - The Rust Programming Language
demoコードと同様に poem.txt
を作成し、下記のように fs::read_to_string
を利用することでファイルを取得可能です。
use std::env; use std::fs; fn main() { // // Accepting Command Line Arguments // let args: Vec<String> = env::args().collect(); println!("{:?}", args); let query = &args[1]; let filename = &args[2]; println!("Searching for {}", query); println!("In file {}", filename); // // Reading a File // let contents = fs::read_to_string(filename).expect("Something went wrong reading the file"); println!("With text:\n{}", contents); }
bash-3.2$ cargo run the poem.txt Compiling minigrep v0.1.0 (/Users/k-hara/Work/training-rust/minigrep) Finished dev [unoptimized + debuginfo] target(s) in 0.33s Running `target/debug/minigrep the poem.txt` ["target/debug/minigrep", "the", "poem.txt"] Searching for the In file poem.txt With text: I'm nobody! Who are you? Are you nobody, too? Then there's a pair of us - don't tell! They'd banish us, you know. How dreary to be somebody! How public, like a frog To tell your name the livelong day To an admiring bog!
Refactoring to Improve Modularity and Error Handling
Refactoring to Improve Modularity and Error Handling - The Rust Programming Language
公式ドキュメントでは、作成したプログラムに対して4つの問題点を提示しています。
main
関数による2つのタスク(コマンドラインの読み込み、ファイルの読み取り)を実行main
の肥大化への懸念
query
やfilename
、contents
のスコープ- スコープ内の変数が多いほど、変数追跡が難しくなることへの懸念
expect
のメッセージ- 失敗の可能性(ファイルがない場合や権限がない場合)などが分からず、UXが悪い
- コマンドライン引数がない場合の処理
index out of bounds
しか出力されないため、UXが悪い
Separation of Concerns for Binary Projects
問題点を解決するために、 main.rs
と lib.rs
に綺麗に分割した方が良いです。
公式ドキュメントより、 main.rs
の責務を掻い摘むと、下記のようになります。
- ロジックは
lib.rs
に分割して、呼び出しをmain.rs
の責務とする - エラーが含まれるロジックに対してのエラー処理を
main.rs
の責務とする
Developing the Library’s Functionality with Test-Driven Development
Developing the Library’s Functionality with Test Driven Development - The Rust Programming Language
search
関数をTDDを利用して作成するということでした。
記載されている手順をまとめると、下記の流れでした。
- 失敗するテスト作成・実行し、予測通りになっているか確認
- テストに合格する十分なコードを作成
- 作成したコードをリファクタリングして、テストをパスか確認
- 手順1から繰り返す。
Working with Environment Variables
Working with Environment Variables - The Rust Programming Language
env::var("CASE_INSENSITIVE").is_err()
により環境変数を利用可能とする。
デモコードでは、CASE_INSENSITIVE
により、大文字・小文字を識別するかどうかを変更している。
Writing Error Messages to Standard Error Instead of Standard Output
Writing Error Messages to Standard Error Instead of Standard Output - The Rust Programming Language
eprintln!
を利用することで、標準エラー出力となる。
まとめ
env::args().collect()
によりコマンドライン引数を利用可能use std::env;
によるenv
の呼び出しが必須
fs::read_to_string
によりファイル呼び出しが利用可能use std::fs;
によるenv
の呼び出しが必須
- メンテナンスのために、
main.rs
、lib.rs
に綺麗に分割が必要 - TDDで開発しよう
env::var("XXXXX").is_err()
により環境変数を利用可能eprintln!
で標準エラー出力
最後に
I/O を絡めた開発手法も含めて、エラーの引き回し方など基本的なプロジェクトの作成方法がおさえられる、良いドキュメントでした。
プロジェクト開発する前に読んでおくべきですね・・・
次は functional language featusです。