【Rust自学】12.8. 将错误信息写入到标准错误

📅 2026/7/23 18:56:58
【Rust自学】12.8. 将错误信息写入到标准错误
12.8 将错误信息写入到标准错误12.8.0. 写在正文之前第12章要做一个实例的项目——一个命令行程序。这个程序是一个grep(Global Regular Expression Print)是一个全局正则搜索和输出的工具。它的功能是在指定的文件中搜索出指定的文字。这个项目分为这么几步- 接收命令行参数- 读取文件- 重构改进模块和错误处理- 使用TDD测试驱动开发开发库功能- 使用环境变量-将错误信息写入标准错误而不是标准输出本文12.8.1. 回顾以下是截止到上一篇文章为止所写出的全部代码。lib.rs:use std::error::Error; use std::fs; pub struct Config { pub query: String, pub filename: String, pub case_sensitive: bool, } impl Config { pub fn new(args: [String]) - ResultConfig, static str { if args.len() 3 { return Err(not enough arguments); } let query args[1].clone(); let filename args[2].clone(); let case_sensitive std::env::var(IGNORE_CASE).is_err(); Ok(Config { query, filename, case_sensitive, }) } } pub fn run(config: Config) - Result(), Boxdyn Error { let contents fs::read_to_string(config.filename)?; let results if config.case_sensitive { search(config.query, contents) } else { search_case_insensitive(config.query, contents) }; for line in results { println!({}, line); } Ok(()) } pub fn searcha(query: str, contents: a str) - Veca str { let mut results Vec::new(); for line in contents.lines() { if line.contains(query) { results.push(line); } } results } pub fn search_case_insensitivea(query: str, contents: a str) - Veca str { let mut results Vec::new(); let query query.to_lowercase(); for line in contents.lines() { if line.to_lowercase().contains(query) { results.push(line); } } results } #[cfg(test)] mod tests { use super::*; #[test] fn case_sensitive() { let query duct; let contents \ Rust: safe, fast, productive. Pick three. Duct tape.; assert_eq!(vec![safe, fast, productive.], search(query, contents)); } #[test] fn case_insensitive() { let query rUsT; let contents \ Rust: safe, fast, productive. Pick three. Trust me.; assert_eq!( vec![Rust:, Trust me.], search_case_insensitive(query, contents) ); } }main.rs:use std::env; use std::process; use minigrep::Config; fn main() { let args: VecString env::args().collect(); let config Config::new(args).unwrap_or_else(|err| { println!(Problem parsing arguments: {}, err); process::exit(1); }); if let Err(e) minigrep::run(config) { println!(Application error: {}, e); process::exit(1); } }12.8.2. 标准输出 vs. 标准错误这个代码目前把所有的信息包括错误信息都打印到终端上了而大多数的终端它都提供两种输出标准输出(stdout)和标准错误(stderr)。一般的信息应该输出到标准输出里而错误信息应该输出到标准错误里。这种区分的好处在于使正常的输出重定向到文件里面而错误信息可以在屏幕上打印。println!这个宏只能将信息打印到标准输出里。而eprintln!这个宏可以把信息输出到标准错误里。我们使用目前的代码在终端中执行这个命令:cargo run output.txt也就是把输出重定向到output.txt里但是这个指令没有带参数也就是说程序应该会报错但由于我们把错误信息也写在标准输出里所以说报错的信息被写在output.txt里了。更好的做法是将错误信息打印到标准错误里这样就可以让标准输出的内容保持整洁不与报错信息混在一起。12.8.3. 修改代码将错误信息打印到标准错误里的代码修改还算简单我们只需要把所有的报错信息从用println!打印改为用eprintln!打印即可。因为所有的报错处理都在main.rs里所以我们只需要对main.rs稍作修改即可lib.rs就完全不需要修改use std::env; use std::process; use minigrep::Config; fn main() { let args: VecString 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); } }然后我们再执行之前那个命令。那个指令没有带参数所以程序会报错但这次它不会把报错信息放在output.txt里而是会直接在终端中打印出来$ cargo run output.txt Problem parsing arguments: not enough arguments然后再试一下正常带参数的$ cargo run -- to poem.txt output.txt输出内容被重定向到output.txt里了打开它Are you nobody, too? How dreary to be somebody!这就是我们想要的结果错误直接在终端打印而正常输出在重定向的文件里。