Why do I get a run error handling custom error types in Rust? [duplicate]

Why is .expect() causing the program to panic?

The short answer is that if the Result is Ok, then .expect() will unwrap and return the contained value in the Ok tuple struct. If the Result is Err, then .expect() will panic with the message you specified.

In your case it appears that one of your Err(_) values is being returned by mytest(), and so the .expect() in main causes a panic. The stack trace should give you a hint as to where things went wrong.

Some debugging tips

Handle the Err instead of panicking

First, I think you should handle the return value of mytest() in the same way that you do the other function that return a Result. This could look like the following.

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

You can of course do something different in each match arm, but it’s usually best to not cause your program to panic if possible.

Tryout the anyhow crate if you’re able

Because you’re ignoring the errors returned by .read_line() and .parse(), you’re losing context as to where the error lies. The .with_context() function can help with this.

Consider structuring your code like the following instead.

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);
}

Then you will get an error like the following

$ 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                                                                    

Now it is more obvious where the error lies. The line variable contains the newline character! As Ibraheem Ahmed pointed out, you need to .trim() line before parsing to ensure it doesn’t contain whitespace.

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))

And now I get the following. =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

CLICK HERE to find out more related problems solutions.

Leave a Comment

Your email address will not be published.

Scroll to Top