当前位置: 首页 > news >正文

【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]) -> Result<Config, &'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<(), Box<dyn 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 search<'a>(query: &str, contents: &'a str) -> Vec<&'a str> { let mut results = Vec::new(); for line in contents.lines() { if line.contains(query) { results.push(line); } } results } pub fn search_case_insensitive<'a>(query: &str, contents: &'a str) -> Vec<&'a 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: 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) = 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: 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); } }

然后我们再执行之前那个命令。那个指令没有带参数,所以程序会报错,但这次它不会把报错信息放在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!

这就是我们想要的结果:错误直接在终端打印,而正常输出在重定向的文件里。

http://www.jsqmd.com/news/1249502/

相关文章:

  • 技术落地复盘:物联网智能锁如何解决网约房民宿合规安防与高运维成本痛点
  • 视频下载神器,现在新的版本支持3000多平台,非常好用,推荐给大家
  • 亨得利服务项目及价格查询|维修地址与服务电话权威信息通告(2026年7月更新) - 亨得利官方
  • LLM Agent工具链:从基础到高级开发实践
  • 【JAVA毕设源码分享】基于springboot大学生就业招聘系统的设计与实现(程序+文档+代码讲解+一条龙定制)
  • 中国叠层母线排市场运行数据分析及未来需求预测报告2026年版
  • V100 32G 全参数训练完整说明
  • 2026年成都双流汽车贴膜综合实力榜:追光车膜成都旗舰店为什么被众多车主推荐 - zhouzhou12321
  • 试了一下 qData 开源版:更像是给数据中台做一次“低成本试跑”
  • 【Rust自学】12.7. 使用环境变量
  • 【Rust自学】2.2. 猜数游戏Pt.2 生成随机数
  • 非接触式激光雪深监测站,气象积雪观测新方案
  • 【爱马仕】新手友好|Hermes Agent 轻量化部署方案,轻松搭建桌面数字助手(含安装包)
  • AI原生应用中的上下文窗口优化与压缩技术
  • 西平装修亲测:2026年7月选这家省心
  • AI数字人口播视频生成技术解析与应用实践
  • 【AI写作多语言翻译终极指南】:20年技术专家亲授5大避坑法则与实时落地框架
  • mysql多条查询结果纵向拼接
  • 揭秘 GitHub 最火的开源 Skills 仓库,夯爆了!30 秒带你用上,让 AI 效率起飞
  • 高效办公 AI 智能体搭建,OpenClaw 整合包极简部署方案(含安装包)
  • AI语义风险防御:认知稳定性测试框架与实践
  • 惠州2026年中央空调回收实测:五星推荐本土老牌商家 - 广东再生资源回收
  • 2026昆明文创商店亚克力定制靠谱厂家推荐 深度选型指南 - 全域品牌推荐
  • 办公自动化专用 OpenClaw 部署教程,内置全套运行组件(含安装包)
  • 海外商标注册成功后,企业还需要做好哪些监测与管理? - 客啦啦视界
  • 可再生能源与电动汽车协同调度的Python实现与优化
  • TI MCU引脚复用与IO控制:DCAN与MibSPI配置实战
  • 怎么刷入Openwrt软路由到了笔记本电脑上并作为旁路由?旁路由应该怎么设置?
  • RAG技术中结构化数据处理五大实战技巧
  • 丹摩平台 | 如何在丹摩平台创建一个自己的GPU云实例