📜  Rust – 错误处理

📅  最后修改于: 2022-05-13 01:54:56.320000             🧑  作者: Mango

Rust – 错误处理

错误基本上是一种意外的行为或事件,它可能导致程序产生不需要的输出或突然终止。错误是在他们的程序中没有人想要的东西。我们可以尝试查找和分析程序中可能导致错误的部分。一旦我们找到了这些部分,我们就可以定义这些部分在遇到错误时应该如何表现。这种为特定代码块查找和定义案例的过程就是我们所说的错误处理。我们应该记住的一件事是,我们无法完全消除错误,但我们可以尝试将它们最小化,或者至少减少它们对我们程序的影响。

在 Rust 中,错误可以分为两类,即可恢复的和不可恢复的

  • 可恢复的错误: 可恢复错误是那些不会导致程序突然终止的错误。示例 - 当我们尝试获取不存在的文件或我们没有打开它的权限时。
  • 不可恢复的错误:不可恢复的错误是那些导致程序突然终止的错误。示例 - 尝试访问大于数组大小的数组索引。

大多数语言不区分这两个错误并使用 Exception 类来克服它们,而 Rust 使用数据类型Result 来处理可恢复的错误和恐慌!宏以在出现不可恢复的错误时停止程序的执行。

我们将首先看看我们应该如何以及在哪里使用恐慌!宏。在它之前,我们将看到它对程序做了什么。

Rust
fn main() {
      panic!("program crashed");
}


Rust
fn main() {
      let v = vec![1, 2, 3];
    println!("{}",v[3])
}


Rust
use std::fs::File;
  
fn main() {
    let f = File::open("gfg.txt");
  println!("{:?}",f);
}


Rust
use std::fs::File;
fn main() {
    
  // file doesn't exist
   let f = File::open("gfg.txt");/
   match f {
      Ok(file)=> {
         println!("file found {:?}",file);
      },
      Err(_error)=> {
          
         // replace it with whatever you want
         // to do if file is not found
         println!("file not found \n");   
      }
   }
}


Rust
fn main(){
   let result = eligible(13);
   match result {
      Ok(age)=>{
         println!("Person eligible to vote with age={}",age);
      },
      Err(msg)=>{
         println!("{}",msg);
      }
   }
}
fn eligible(age:i32)->Result {
   if age>=18 {
      return Ok(age);
   } else {
      return Err("Not Eligible..Wait for some years".to_string());
   }
}


Rust
use std::fs::File;
  
fn main() {
    let f = File::open("gfg.txt").unwrap();
}


Rust
use std::fs::File;
  
fn main() {
    let f = File::open("hello.txt").expect("Failed to open gfg.txt");
}


输出:

thread 'main' panicked at 'program crashed', main.rs:2:7

因此,它基本上会停止程序的执行并打印我们在其参数中传递的内容。

恐慌!宏可能在我们使用的库文件中,让我们看看:

fn main() {
      let v = vec![1, 2, 3];
    println!("{}",v[3])
}

输出:

thread 'main' panicked at 'index out of bounds: the len is 3 but the index is 3', main.rs:3:19

由于我们试图访问超出向量边界的元素,因此它称为恐慌!宏。

如果我们的代码可能最终处于错误状态,我们应该只在条件下使用恐慌。糟糕的状态是当某些假设、保证、合同或不变量被破坏时,例如当无效值、矛盾值或缺失值被传递给我们的代码以及以下至少一项时:-

  • 如果在蓝色月亮中出现一次不良状态。
  • 在此之后您的代码需要依赖于不处于这种糟糕状态。
  • 在您使用的类型中编码此信息不是一个好方法。

可恢复的错误

Result 是一个枚举数据类型,它有两个变体 OK 和 Err,它的定义是这样的



enum Result {
    Ok(T),
    Err(E),
}

T 和 E 是泛型类型参数,其中 T 表示将在 Ok 变体中的成功案例中返回的值的类型,而 E 表示将在 Err 变体中的失败案例中返回的错误类型。

use std::fs::File;
  
fn main() {
    let f = File::open("gfg.txt");
  println!("{:?}",f);
}

输出:

Err(Os { code: 2, kind: NotFound, message: "No such file or directory" })

由于文件 gfg.txt 不存在,所以文件返回了 Err 实例。如果找到了文件 gfg.txt,则将返回该文件的一个实例。

如果像上述情况一样没有找到文件,那么最好让用户检查文件名、文件位置或再次提供文件规格或任何情况需要。

use std::fs::File;
fn main() {
    
  // file doesn't exist
   let f = File::open("gfg.txt");/
   match f {
      Ok(file)=> {
         println!("file found {:?}",file);
      },
      Err(_error)=> {
          
         // replace it with whatever you want
         // to do if file is not found
         println!("file not found \n");   
      }
   }
}

输出:

file not found 

在上面的程序中,它基本上匹配了结果的返回类型,并相应地执行了任务。

让我们根据业务逻辑创建我们自己的错误。假设我们想要在 18 岁以下的人尝试申请选民 ID 时产生错误。



fn main(){
   let result = eligible(13);
   match result {
      Ok(age)=>{
         println!("Person eligible to vote with age={}",age);
      },
      Err(msg)=>{
         println!("{}",msg);
      }
   }
}
fn eligible(age:i32)->Result {
   if age>=18 {
      return Ok(age);
   } else {
      return Err("Not Eligible..Wait for some years".to_string());
   }
}

输出:

Not Eligible..Wait for some years

如果我们想在遇到可恢复的错误后中止程序,那么我们可以使用 panic!宏并为了简化过程 Rust 提供了两个方法 unwrap() 和 expect()。

  • 解包()

use std::fs::File;
  
fn main() {
    let f = File::open("gfg.txt").unwrap();
}

输出:

thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value:
Os { code: 2, kind: NotFound, message: "No such file or directory" }', main.rs:17:14

unwrap() 调用恐慌!宏在文件未找到的情况下,如果找到文件,则返回文件处理程序实例。虽然 unwrap() 使程序更短,但是当我们的程序中有太多 unwrap() 方法时,那么对于调用 panic 的 unwrap() 方法变得有点混乱!宏。所以我们需要一些可以产生定制消息的东西。在这种情况下,expect() 方法就派上用场了。

  • 预计()

use std::fs::File;
  
fn main() {
    let f = File::open("hello.txt").expect("Failed to open gfg.txt");
}

输出:

thread 'main' panicked at 'Failed to open gfg.txt:
Os { code: 2, kind: NotFound, message: "No such file or directory" }', main.rs:17:14

我们传递了我们的信息来恐慌!宏通过预期的参数。