【问题标题】:Why do I get a run error handling custom error types in Rust? [duplicate]为什么在 Rust 中处理自定义错误类型时会出现运行错误? [复制]
【发布时间】:2021-02-12 13:24:25
【问题描述】:

我在使用 .expect() 处理错误时遇到问题。
这是我的代码:

src/main.rs

mod myerrors;

fn main() {
    mytest().expect("incorrrect number");
    //let shows: Vec<Show> = download().expect("read error");
    //print(shows);
}

fn mytest() -> std::result::Result<i8, myerrors::MyError>
{
    let stdin = std::io::stdin();
    let mut line: String = String::new();
    match stdin.read_line(&mut line)
    {
        Ok(_) => {},
        Err(_) => return Err(myerrors::DownloadError),
    };
    let num: i8 = match line.parse::<i8>()
    {
        Ok(num) => num,
        Err(_) => return Err(myerrors::MyError),
    };
    return Ok(num);
}

src/myerrors.rs

pub struct MyError;

impl std::fmt::Debug for MyError
{
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result
    {
        f.debug_struct("DownloadError").finish()
    }
}

它会构建,但在任何输入 thread 'main' 在 'incorrrect number: DownloadError', src/main.rs:4:14 处发生恐慌后崩溃。

【问题讨论】:

  • line.parse::&lt;i8&gt;() 正在返回错误。 .expect 试图解开结果,但因为这是一个错误而恐慌。这是.expect 的预期行为。问题在于你的代码逻辑,而不是错误处理
  • 您的意见是什么?您希望发生什么?
  • @IbraheemAhmed 我修复了这个问题,但仍然存在相同的错误
  • @kmdreko 即使我输入“123”,我也会在 main 中出现恐慌错误

标签: rust


【解决方案1】:

为什么 .expect() 会导致程序崩溃?

简短的回答是,如果ResultOk,那么.expect() 将展开并返回Ok 元组结构中包含的值。如果ResultErr,那么.expect() 将因您指定的消息而恐慌。

在您的情况下,mytest() 返回了您的Err(_) 值之一,因此main 中的.expect() 引起了恐慌。堆栈跟踪应该会提示您哪里出了问题。

一些调试技巧

处理错误而不是恐慌

首先,我认为您应该像处理返回Result 的其他函数一样处理mytest() 的返回值。这可能如下所示。

fn main() {
    match mytest() {
      Ok(_) => println!("ok!");
      Err(e) => println!("Error: {:?}", e);
    }
}

您当然可以在每个匹配组中执行不同的操作,但通常最好不要让您的程序出现恐慌。

如果可以的话,尝试一下无论如何的板条箱

因为您忽略了.read_line().parse() 返回的错误,所以您将失去关于错误所在位置的上下文。 .with_context() 函数可以帮助解决这个问题。

考虑改用以下结构来构建您的代码。

use anyhow::{Context, Result};

fn main() {
    match mytest() {
        Ok(num) => println!("Parsed: {}", num),
        Err(e) => println!("{:?}", e),
    }
}

fn mytest() -> Result<i8> {
    let stdin = std::io::stdin();
    let mut line: String = String::new();
    match stdin.read_line(&mut line) {
        Ok(_) => {}
        Err(e) => return Err(e).with_context(|| format!("Unexpected failure reading stdin")),
    };
    let num: i8 = match line.parse::<i8>() {
        Ok(num) => num,
        Err(e) => {
            return Err(e).with_context(|| format!("Unexpected failure parsing line: {:?}", line))
        }
    };
    return Ok(num);
}

然后你会得到类似下面的错误

$ cargo run                                                                                          
   Compiling stdin-debug v0.1.0 (/Users/chcl/Development/learning-rust/projects/stdin-debug)         
    Finished dev [unoptimized + debuginfo] target(s) in 0.39s                                        
     Running `target/debug/stdin-debug`                                                              
123                                                                                                  
Unexpected failure parsing line: "123\n"                                                             
                                                                                                     
Caused by:                                                                                           
    invalid digit found in string                                                                    

现在错误在哪里更明显了。 line 变量包含换行符!正如 Ibraheem Ahmed 指出的那样,您需要在解析之前 .trim() 行,以确保它不包含空格。

diff --git a/src/main.rs b/src/main.rs
index d07677a..4172e4e 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -14,7 +14,7 @@ fn mytest() -> Result<i8> {
         Ok(_) => {}
         Err(e) => return Err(e).with_context(|| format!("Unexpected failure reading stdin")),
     };
-    let num: i8 = match line.parse::<i8>() {
+    let num: i8 = match line.trim().parse::<i8>() {
         Ok(num) => num,
         Err(e) => {
             return Err(e).with_context(|| format!("Unexpected failure parsing line: {:?}", line))

现在我得到以下信息。 =D

$ cargo run
   Compiling stdin-debug v0.1.0 (/Users/chcl/Development/learning-rust/projects/stdin-debug)
    Finished dev [unoptimized + debuginfo] target(s) in 0.38s
     Running `target/debug/stdin-debug`
123
Parsed: 123

【讨论】:

  • 结果不需要 2 种类型。我按照这个例子得到了一个错误,结果需要 2 个类型的参数。
  • 这不是std的结果,这是anyhow的结果,即Result
【解决方案2】:

问题在于包含用户输入的line 变量包含额外的空格。当您尝试将其解析为整数时,它会失败,并且您的代码会出现恐慌。您可以通过修剪用户输入来解决此问题:

// note the use of `.trim()`
let num: i8 = match line.trim().parse::<i8>() {
  Ok(num) => num,
  Err(_) => return Err(myerrors::DownloadError),
};

【讨论】:

  • 我在示例中更改了一些不清楚的方面。我的真实案例更复杂,在这里展示。如果我需要返回值或错误,我该怎么办?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-22
相关资源
最近更新 更多