====== 错误处理 ====== ===== Rust 的错误哲学 ===== Rust 将错误分为两类: * **可恢复的错误** - 使用 ''Result'' * **不可恢复的错误** - 使用 ''panic!'' ===== panic! 宏 ===== ''panic!'' 用于遇到无法处理的错误时终止程序: fn main() { panic!("程序发生了严重错误!崩溃!"); // 后续代码不会执行 } 常见的 panic 场景: fn main() { let v = vec![1, 2, 3]; v[99]; // 索引越界 -> panic! } ===== Result 类型 ===== ''Result'' 是处理可恢复错误的标准方式: enum Result { Ok(T), // 成功 Err(E), // 失败 } ==== 基础使用 ==== use std::fs::File; use std::io::ErrorKind; fn main() { let f = File::open("hello.txt"); let f = match f { Ok(file) => file, Err(error) => match error.kind() { ErrorKind::NotFound => match File::create("hello.txt") { Ok(fc) => fc, Err(e) => panic!("创建文件失败: {:?}", e), }, other_error => { panic!("打开文件失败: {:?}", other_error) } }, }; } ==== unwrap 和 expect ==== 简单快速的错误处理方式: fn main() { // 成功则返回值,失败则 panic let f = File::open("hello.txt").unwrap(); // 类似 unwrap,但自定义 panic 信息 let f = File::open("hello.txt") .expect("无法打开 hello.txt"); } ==== ? 运算符 ==== ''?'' 运算符是错误传播的语法糖:成功则解包,失败则提前返回错误。 use std::fs::File; use std::io::{self, Read}; fn read_username_from_file() -> Result { let mut f = File::open("hello.txt")?; // 失败时 return Err let mut s = String::new(); f.read_to_string(&mut s)?; // 失败时 return Err Ok(s) } fn main() { match read_username_from_file() { Ok(name) => println!("用户名: {}", name), Err(e) => println!("读取失败: {}", e), } } ''?'' 还可以链式调用: fn read_username() -> Result { let mut s = String::new(); File::open("hello.txt")?.read_to_string(&mut s)?; Ok(s) } ===== Option 类型处理 ===== ''Option'' 用于值可能不存在的情况: fn find_first_word(s: &str) -> Option<&str> { let bytes = s.as_bytes(); for (i, &item) in bytes.iter().enumerate() { if item == b' ' { return Some(&s[..i]); } } None // 没有空格返回 None } fn main() { match find_first_word("hello world") { Some(word) => println!("第一个词: {}", word), None => println!("没有找到空格"), } // Option 也可用 ? 运算符 fn try_find(s: &str) -> Option<&str> { let word = find_first_word(s)?; // None 则提前返回 Some(word) } } ===== 组合子方法 ===== ''Result'' 和 ''Option'' 提供了丰富的组合子方法: fn main() { // map - 转换内部值 let result: Result = Ok(5); let mapped = result.map(|x| x * 2); // Ok(10) // and_then - 链式操作 let result = result.and_then(|x| Ok(x + 3)); // Ok(8) // unwrap_or - 提供默认值 let default: Result = Err("error"); let value = default.unwrap_or(0); // 0 // ok_or - Option 转 Result let option: Option = Some(5); let result = option.ok_or("值不存在"); // Ok(5) } ===== 自定义错误类型 ===== use std::fmt; #[derive(Debug)] enum MyError { IoError(std::io::Error), ParseError(String), } impl fmt::Display for MyError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { MyError::IoError(e) => write!(f, "IO 错误: {}", e), MyError::ParseError(s) => write!(f, "解析错误: {}", s), } } } impl std::error::Error for MyError {} // 实现标准 Error trait ===== 本章实践 ===== use std::io::{self, BufRead}; fn read_and_parse() -> Result { let mut line = String::new(); io::stdin().read_line(&mut line) .map_err(|e| format!("读取输入失败: {}", e))?; line.trim().parse::() .map_err(|_| "无法解析为整数".to_string()) } fn main() { println!("请输入一个整数:"); match read_and_parse() { Ok(n) => println!("你输入了: {}", n), Err(e) => println!("错误: {}", e), } } ===== 本章小结 ===== * ''panic!'' 用于不可恢复的错误 * ''Result'' 处理可恢复的错误 * ''unwrap'' 和 ''expect'' 快速解包(失败时 panic) * ''?'' 运算符传播错误,写出简洁代码 * ''map''、''and_then''、''unwrap_or'' 等组合子丰富处理方式 * 自定义错误类型实现 ''Error'' trait