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.