Rust 將錯誤信息輸出到標(biāo)準(zhǔn)錯誤而不是標(biāo)準(zhǔn)輸出

2023-03-22 15:12 更新
ch12-06-writing-to-stderr-instead-of-stdout.md
commit c5c12e911b20fac20eefc511f6fe8d432a8e5ec2

目前為止,我們將所有的輸出都通過 println! 寫到了終端。大部分終端都提供了兩種輸出:標(biāo)準(zhǔn)輸出standard output,stdout)對應(yīng)一般信息,標(biāo)準(zhǔn)錯誤standard error,stderr)則用于錯誤信息。這種區(qū)別允許用戶選擇將程序正常輸出定向到一個文件中并仍將錯誤信息打印到屏幕上。

但是 println! 宏只能夠打印到標(biāo)準(zhǔn)輸出,所以我們必須使用其他方法來打印到標(biāo)準(zhǔn)錯誤。

檢查錯誤應(yīng)該寫入何處

首先,讓我們觀察一下目前 minigrep 打印的所有內(nèi)容是如何被寫入標(biāo)準(zhǔn)輸出的,包括那些應(yīng)該被寫入標(biāo)準(zhǔn)錯誤的錯誤信息??梢酝ㄟ^將標(biāo)準(zhǔn)輸出流重定向到一個文件同時有意產(chǎn)生一個錯誤來做到這一點。我們沒有重定向標(biāo)準(zhǔn)錯誤流,所以任何發(fā)送到標(biāo)準(zhǔn)錯誤的內(nèi)容將會繼續(xù)顯示在屏幕上。

命令行程序被期望將錯誤信息發(fā)送到標(biāo)準(zhǔn)錯誤流,這樣即便選擇將標(biāo)準(zhǔn)輸出流重定向到文件中時仍然能看到錯誤信息。目前我們的程序并不符合期望;相反我們將看到它將錯誤信息輸出保存到了文件中。

我們通過 > 和文件名 output.txt 來運行程序,我們期望重定向標(biāo)準(zhǔn)輸出流到該文件中。在這里,我們沒有傳遞任何參數(shù),所以會產(chǎn)生一個錯誤:

$ cargo run > output.txt

> 語法告訴 shell 將標(biāo)準(zhǔn)輸出的內(nèi)容寫入到 output.txt 文件中而不是屏幕上。我們并沒有看到期望的錯誤信息打印到屏幕上,所以這意味著它一定被寫入了文件中。如下是 output.txt 所包含的:

Problem parsing arguments: not enough arguments

是的,錯誤信息被打印到了標(biāo)準(zhǔn)輸出中。像這樣的錯誤信息被打印到標(biāo)準(zhǔn)錯誤中將會有用得多,將使得只有成功運行所產(chǎn)生的輸出才會寫入文件。我們接下來就修改。

將錯誤打印到標(biāo)準(zhǔn)錯誤

讓我們?nèi)缡纠?12-24 所示的代碼改變錯誤信息是如何被打印的。得益于本章早些時候的重構(gòu),所有打印錯誤信息的代碼都位于 main 一個函數(shù)中。標(biāo)準(zhǔn)庫提供了 eprintln! 宏來打印到標(biāo)準(zhǔn)錯誤流,所以將兩個調(diào)用 println! 打印錯誤信息的位置替換為 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! 將錯誤信息寫入標(biāo)準(zhǔn)錯誤而不是標(biāo)準(zhǔn)輸出

將 println! 改為 eprintln! 之后,讓我們再次嘗試用同樣的方式運行程序,不使用任何參數(shù)并通過 > 重定向標(biāo)準(zhǔn)輸出:

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

現(xiàn)在我們看到了屏幕上的錯誤信息,同時 output.txt 里什么也沒有,這正是命令行程序所期望的行為。

如果使用不會造成錯誤的參數(shù)再次運行程序,不過仍然將標(biāo)準(zhǔn)輸出重定向到一個文件,像這樣:

$ cargo run to poem.txt > output.txt

我們并不會在終端看到任何輸出,同時 output.txt 將會包含其結(jié)果:

文件名: output.txt

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

這一部分展示了現(xiàn)在我們適當(dāng)?shù)氖褂昧顺晒r產(chǎn)生的標(biāo)準(zhǔn)輸出和錯誤時產(chǎn)生的標(biāo)準(zhǔn)錯誤。

總結(jié)

在這一章中,我們回顧了目前為止的一些主要章節(jié)并涉及了如何在 Rust 環(huán)境中進(jìn)行常規(guī)的 I/O 操作。通過使用命令行參數(shù)、文件、環(huán)境變量和打印錯誤的 eprintln! 宏,現(xiàn)在你已經(jīng)準(zhǔn)備好編寫命令行程序了。通過結(jié)合前幾章的知識,你的代碼將會是組織良好的,并能有效的將數(shù)據(jù)存儲到合適的數(shù)據(jù)結(jié)構(gòu)中、更好的處理錯誤,并且還是經(jīng)過良好測試的。

接下來,讓我們探索一些 Rust 中受函數(shù)式編程語言影響的功能:閉包和迭代器。


以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號