標準出力ではなく標準エラーにエラーメッセージを書き込む

現時点では、すべての出力をprintln!関数を使用して端末に書き込んでいます。多くの端末は、 2種類の出力を提供します: 普通の情報用の標準出力(stdout)とエラーメッセージ用の標準エラー出力(stderr)です。 この差異のおかげで、ユーザは、エラーメッセージを画面に表示しつつ、 プログラムの成功した出力をファイルにリダイレクトすることを選択できます。

println!関数は、標準出力に出力する能力しかないので、標準エラーに出力するには他のものを使用しなければなりません。

エラーが書き込まれる場所を確認する

まず、minigrepに出力される中身が、代わりに標準エラーに書き込みたいいかなるエラーメッセージも含め、 どのように標準出力に書き込まれているかを観察しましょう。意図的にエラーを起こしつつ、 ファイルに標準出力ストリームをリダイレクトすることでそうします。標準エラーストリームはリダイレクトしないので、 標準エラーに送られる内容は、すべて画面に表示され続けます。

コマンドラインプログラムは、エラーメッセージを標準エラー出力に送信していると期待されているので、 標準出力ストリームをファイルにリダイレクトしても、画面にエラーメッセージが見られます。 我々のプログラムは、現状、いい振る舞いをしていません: 代わりにファイルにエラーメッセージ出力を保存するところを、 目撃するところです!

この動作をデモする方法は、>と標準出力ストリームをリダイレクトする先のファイル名、output.txtでプログラムを走らせることによります。 引数は何も渡さず、そうするとエラーが起きるはずです:

$ cargo run > output.txt

>記法により、標準出力の中身を画面の代わりにoutput.txtに書き込むようシェルは指示されます。 画面に出力されると期待していたエラーメッセージは見られないので、ファイルに入っているということでしょう。 以下がoutput.txtが含んでいる内容です:

Problem parsing arguments: not enough arguments

そうです。エラーメッセージは標準出力に出力されているのです。このようなエラーメッセージは標準エラーに出力され、 成功した状態のデータのみがファイルに残ると遥かに有用です。それを変更します。

エラーを標準エラーに出力する

リスト12-24のコードを使用して、エラーメッセージの出力の仕方を変更します。この章の前で行ったリファクタリングのため、 エラーメッセージを出力するコードはすべて1関数、mainにあります。標準ライブラリは、 標準エラーストリームに出力するeprintln!マクロを提供しているので、 println!を呼び出してエラーを出力していた2箇所を代わりにeprintln!を使うように変更しましょう。

ファイル名: src/main.rs

fn main() {
    let args: Vec<String> = env::args().collect();

    let config = Config::new(&args).unwrap_or_else(|err| {
        eprintln!("Problem parsing arguments: {}", err);
        process::exit(1);
    });

    if let Err(e) = minigrep::run(config) {
        eprintln!("Application error: {}", e);

        process::exit(1);
    }
}

リスト12-24: eprintln!を使って標準出力ではなく、標準エラーにエラーメッセージを書き込む

println!eprintln!に変えてから、再度同じようにプログラムを実行しましょう。 引数なしかつ、標準出力を>でリダイレクトしてね:

$ cargo run > output.txt
Problem parsing arguments: not enough arguments

これで、エラーは画面に見えつつ、output.txtは何も含まなくなり、これはコマンドラインプログラムに期待する動作です。

再度、標準出力をファイルにリダイレクトしてエラーは起こさない引数でプログラムを走らせましょう。以下のようにですね:

$ cargo run to poem.txt > output.txt

ターミナルには出力は見られず、output.txtに結果が含まれます:

ファイル名: output.txt

Are you nobody, too?
How dreary to be somebody!

これは、もう成功した出力には標準出力を、エラー出力には標準エラーを適切に使用していることをデモしています。

まとめ

この章では、ここまでに学んできた主要な概念の一部を念押しし、Rustで入出力処理を行う方法を講義しました。 コマンドライン引数、ファイル、環境変数、そしてエラー出力にeprintln!マクロを使用することで、 もう、コマンドラインアプリケーションを書く準備ができています。以前の章の概念を使用することで、 コードはうまく体系化され、適切なデータ構造に効率的にデータを保存し、エラーをうまく扱い、 よくテストされるでしょう。

次は、関数型言語に影響されたRust機能を一部探究します: クロージャとイテレータです。