总体原则

  • 在定义一个可能失败的函数时,优先考虑返回 Result
  • 否则就 panic!

    编写示例、原型代码、测试

  • 可以使用panic!

    • 演示某些概念:unwrap
    • 原型代码:unwrap、expect
    • 测试:unwrap、expect

      有时你比编译器掌握更多的信息

  • 你可以确定 Result 就是 Ok: unwrap ```rust use std::net::IpAddr;

fn main() { let home: IpAddr = “127.0.0.1”.parse().unwrap(); }

  1. <a name="vXsSf"></a>
  2. ### 错误处理的指导性建议
  3. - 当代码最终可能处于损坏状态时,最好使用 panic!
  4. - 损坏状态(Bad state): 某些假设、保证、约定或不可变性被打破
  5. - 例如非法的值、矛盾的值或空缺的值被传入代码
  6. - 以及下列中的一条
  7. - 这种损坏状态并不是预期能够偶尔发生的事情
  8. - 在此之后,您的代码如果处于这种损坏状态就无法运行
  9. - 在你使用的类型中没有一个好的办法将这些信息(处于损坏状态)进行编码
  10. <a name="Oq7fk"></a>
  11. ### 场景建议
  12. - 调用你的代码,传入无意义的参数值:panic!
  13. - 调用外部不可控代码,返回非法状态,你无法修复:panic!
  14. - 如果失败是可预期的:Result
  15. - 当你的代码对值进行操作,首先应该验证这些值:panic!
  16. <a name="aSSaP"></a>
  17. ### 为验证创建自定义类型
  18. 之前的猜数游戏
  19. ```rust
  20. use rand::Rng; // trait 接口定义了随机数生成器需要的方法
  21. use std::cmp::Ordering;
  22. use std::io; // prelude
  23. fn main() {
  24. println!("猜数!");
  25. let secret_number = rand::thread_rng().gen_range(1..101); // i32 u32 i64
  26. loop {
  27. println!("猜测一个数");
  28. let mut guess = String::new();
  29. io::stdin().read_line(&mut guess).expect("无法读取行");
  30. // shadow
  31. // let guess: u32 = guess.trim().parse().expect("请输入一个数字");
  32. let guess: i32 = match guess.trim().parse() {
  33. Ok(num) => num,
  34. Err(_) => continue,
  35. };
  36. if guess < 1 || guess > 100 {
  37. println!("The guess number will be between 1 and 100.");
  38. continue;
  39. }
  40. println!("你猜测的数是: {}", guess);
  41. match guess.cmp(&secret_number) {
  42. Ordering::Less => println!("Too small!"), // arm
  43. Ordering::Greater => println!("To big!"),
  44. Ordering::Equal => {
  45. println!("You win!");
  46. break;
  47. }
  48. }
  49. }
  50. }
  • 创建新的类型,把验证逻辑放在构造实例的函数里
  • getter: 返回字段数据
    • 字段是私有的:外部无法直接对字段赋值 ```rust use rand::Rng; use std::cmp::Ordering; use std::io;

pub struct Guess { value: i32, }

impl Guess { pub fn new(value: i32) -> Guess { if value < 1 || value > 100 { panic!(“Guess value must be between 1 and 100, got {}”, value); } Guess { value } } pub fn value(&self) -> i32 { self.value } }

fn main() { println!(“猜数!”); let secretnumber = rand::thread_rng().gen_range(1..101); loop { println!(“猜测一个数”); let mut guess = String::new(); io::stdin().read_line(&mut guess).expect(“无法读取行”); let guess: i32 = match guess.trim().parse() { Ok(num) => num, Err() => continue, }; // 如果能成功创建实例,说明它通过了验证,如果发生 panic 说明它没有通过验证 let guess = Guess::new(guess); println!(“你猜测的数是: {}”, guess.value); match guess.value.cmp(&secret_number) { Ordering::Less => println!(“Too small!”), // arm Ordering::Greater => println!(“To big!”), Ordering::Equal => { println!(“You win!”); break; } } } } ``` https://docs.rs/rand/0.8.3/rand/trait.Rng.html#method.gen_range