This question already has an answer here:
Why am I getting "unused Result which must be used ... Result may be an Err variant, which should be handled" even though I am handling it?
(1 answer)
Closed 2 years ago.
I'm doing rust cli tutorials from https://rust-cli.github.io/book/tutorial/testing.html and got stuck with a compiler warning:
unused `std::result::Result` that must be used
--> src/main.rs:15:13
|
15 | writeln!(writer, "{}", line);
Here is the whole code:
use exitfailure::ExitFailure;
use failure::ResultExt;
use structopt::StructOpt;
#[derive(StructOpt)]
struct Cli {
pattern: String,
#[structopt(parse(from_os_str))]
path: std::path::PathBuf,
}
fn find_matches(content: &str, pattern: &str, mut writer: impl std::io::Write) {
for line in content.lines() {
if line.contains(pattern) {
writeln!(writer, "{}", line);
}
}
}
#[test]
fn find_a_match() {
let mut result = Vec::new();
find_matches("lorem ipsum\ndolor sit amet", "lorem", &mut result);
assert_eq!(result, b"lorem ipsum\n");
}
fn main() -> Result<(), ExitFailure> {
let args = Cli::from_args();
let content = std::fs::read_to_string(&args.path)
.with_context(|_| format!("could not read file `{}`", &args.path.display()))?;
find_matches(&content, &args.pattern, &mut std::io::stdout());
Ok(())
}
Why do I get this warning?
writer that you pass to writeln! can be arbitrary std::io::Write object, in particular a file writer, a network writer or whatever. Those can fail when you write to them and so writeln!(...) returns a Result<T,E>, which indicates whether write operation completed successfully or failed.
If you don't use this Result, then you can potentially miss when an error is occurred, so the logic of your program might fail then. (note that Rust doesn't have exceptions, so there are in general two ways of telling a problem: in a return type like Option, Result, bool, or whatever; or via panic!, assert! macros that will crash your program with no chance to recover if something went wrong).
So ideally you shouldn't ignore this Result in any way. You can do like this for now
for line in content.lines() {
if line.contains(pattern) {
if let Err(e) = writeln!(writer, "{}", line) {
println!("Writing error: {}", e.to_string());
}
}
}
If you wish, later on you can make a more adequate reaction to the error (like retrying writing)
Related
I would like to have the details of an error be propagated upwards. I used error-chain previously, but that has not been maintained or kept compatible with the rest of the ecosystem as far as i can tell.
For example, in this example:
use std::str::FromStr;
use anyhow::Result;
fn fail() -> Result<u64> {
Ok(u64::from_str("Some String")?)
}
fn main() {
if let Err(e) = fail(){
println!("{:?}", e);
}
The error i am getting is:
invalid digit found in string
I would need the error message to have the key details, including at the point of failure, for example:
- main: invalid digit found in string
- fail: "Some String" is not a valid digit
What's the best way of doing this?
anyhow provides the context() and with_context() methods for that:
use anyhow::{Context, Result};
use std::str::FromStr;
fn fail() -> Result<u64> {
let s = "Some String";
Ok(u64::from_str(s).with_context(|| format!("\"{s}\" is not a valid digit"))?)
}
fn main() {
if let Err(e) = fail() {
println!("{:?}", e);
}
}
"Some String" is not a valid digit
Caused by:
invalid digit found in string
If you want custom formatting, you can use the Error::chain() method:
if let Err(e) = fail() {
for err in e.chain() {
println!("{err}");
}
}
"Some String" is not a valid digit
invalid digit found in string
And if you want additional details (e.g. where the error happened), you can use a custom error type and downcast it (for error source you can also capture a backtrace).
This is a tricky thing to accomplish and I'm not sure that there is a simple and non-invasive way to capture all of the details of any possible error without knowledge of the particular function being invoked. For example, we may want to display some arguments to the function call that failed, but evaluating other arguments might be problematic -- they may not even be able to be turned into strings.
Maybe the argument is another function call, too, so should we capture its arguments or only its return value?
I whipped up this example quickly to show that we can at least fairly trivially capture the exact source expression. It provides a detail_error! macro that takes an expression that produces Result<T, E> and emits an expression that procudes Result<T, DetailError<E>>. The DetailError wraps the original error value and additionally contains a reference to a string of the original source code fed to the macro.
use std::error::Error;
use std::str::FromStr;
#[derive(Debug)]
struct DetailError<T: Error> {
expr: &'static str,
cause: T,
}
impl<T: Error> DetailError<T> {
pub fn new(expr: &'static str, cause: T) -> DetailError<T> {
DetailError { expr, cause }
}
// Some getters we don't use in this example, but should be present to have
// a complete API.
#[allow(dead_code)]
pub fn cause(&self) -> &T {
&self.cause
}
#[allow(dead_code)]
pub fn expr(&self) -> &'static str {
self.expr
}
}
impl<T: Error> Error for DetailError<T> { }
impl<T: Error> std::fmt::Display for DetailError<T> {
fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
write!(f, "While evaluating ({}): ", self.expr)?;
std::fmt::Display::fmt(&self.cause, f)
}
}
macro_rules! detail_error {
($e:expr) => {
($e).map_err(|err| DetailError::new(stringify!($e), err))
}
}
fn main() {
match detail_error!(u64::from_str("Some String")) {
Ok(_) => {},
Err(e) => { println!("{}", e); }
};
}
This produces the runtime output:
While evaluating (u64::from_str("Some String")): invalid digit found in string
Note that this only shows the string because it's a literal in the source. If you pass a variable/parameter instead, you will see that identifier in the error message instead of the string.
When you run your app with the environment variable RUST_BACKTRACE set to 1 or full, you'll get more error details, without the need to recompile your program. That, however, doesn't mean you're going to get an extra message like "Some String" is not a valid digit, as the parsing function simply doesn't generate such.
I'm reading the documentation for File:
//..
let mut file = File::create("foo.txt")?;
//..
What is the ? in this line? I do not recall seeing it in the Rust Book before.
As you may have noticed, Rust does not have exceptions. It has panics, but their use for error-handling is discouraged (they are meant for unrecoverable errors).
In Rust, error handling uses Result. A typical example would be:
fn halves_if_even(i: i32) -> Result<i32, Error> {
if i % 2 == 0 {
Ok(i / 2)
} else {
Err(/* something */)
}
}
fn do_the_thing(i: i32) -> Result<i32, Error> {
let i = match halves_if_even(i) {
Ok(i) => i,
Err(e) => return Err(e),
};
// use `i`
}
This is great because:
when writing the code you cannot accidentally forget to deal with the error,
when reading the code you can immediately see that there is a potential for error right here.
It's less than ideal, however, in that it is very verbose. This is where the question mark operator ? comes in.
The above can be rewritten as:
fn do_the_thing(i: i32) -> Result<i32, Error> {
let i = halves_if_even(i)?;
// use `i`
}
which is much more concise.
What ? does here is equivalent to the match statement above with an addition. In short:
It unpacks the Result if OK
It returns the error if not, calling From::from on the error value to potentially convert it to another type.
It's a bit magic, but error handling needs some magic to cut down the boilerplate, and unlike exceptions it is immediately visible which function calls may or may not error out: those that are adorned with ?.
One example of the magic is that this also works for Option:
// Assume
// fn halves_if_even(i: i32) -> Option<i32>
fn do_the_thing(i: i32) -> Option<i32> {
let i = halves_if_even(i)?;
// use `i`
}
The ? operator, stabilized in Rust version 1.13.0 is powered by the (unstable) Try trait.
See also:
Is the question mark operator ? equivalent to the try! macro?
Why do try!() and ? not compile when used in a function that doesn't return Option or Result?
It is a postfix operator that unwraps Result<T, E> and Option<T> values.
If applied to Result<T, E>, it unwraps the result and gives you the inner value, propagating the error to the calling function.
let number = "42".parse::<i32>()?;
println!("{:?}", number); // 42
When applied to an Option<T>, it propagates None to the caller, leaving you the content of the Some branch to deal with.
let val = Some(42)?;
println!("{:?}", val); // 42
The ? operator can only be used in a function that returns Result or Option like so:
use std::num::ParseIntError;
fn main() -> Result<(), ParseIntError> {
let number = "42".parse::<i32>()?;
println!("{:?}", number);
Ok(())
}
It is a convenience offered by Rust, that eliminates boilerplate code and makes function's implementation simpler.
It is used for propagating errors. Sometimes we write code that might fail but we do not want to catch and handle error immediately. Your code will not be readable if you have too much code to handle the error in every place. Instead, if an error occurs, we might want to let our caller deal with it. We want errors to propagate up the call stack.
// file type is Result if "?" is not used
// file:Result<File,Error>
let mut file = File::create("foo.txt");
// file type is File if "?" is used
// file:File
let mut file = File::create("foo.txt")?;
// if an error occurs, code after this line will not be executed
// function will return the error
The behavior of ? depends on whether this function returns a successful result or an error result:
If it is a success, it unwraps the Result to get the success value inside. Value is assigned to the variable file
If the result is an error, the error is NOT assigned to the variable file. Error is returned by the function to the caller
Using ? same as this code
let mut file = match File::create("foo.txt") {
Err(why) => panic!("couldn't create {}: {}", display, why),
Ok(file) => file,
};
? also works similarly with the Option type. In a function that returns Option, you
can use ? to unwrap a value and return early in the case of None :
The existing answers are all great! I would like to give a small code snippet to demo the use of From::from() behand this question mark:
fn _parse(str: &str) -> Result<i32, &str> {
if let Ok(num) = str.parse::<i32>() {
Ok(num)
} else {
Err(str)
}
}
fn parse(str: &str) -> Result<(), String> {
let num = _parse(str)?;
println!("{}", num);
Ok(())
}
The use of ? in function parse() can be manually rewritten as:
fn parse(str: &str) -> Result<(), String> {
match _parse(str) {
Ok(n) => {
println!("{}", n);
Ok(())
}
Err(str) => Err(<String as From<&str>>::from(str)),
}
}
Why is this exception being thrown, and how I can fix it? This is a piece of code that I am working on to get user input. I want to eventually use enums instead of if else statements, but I don't understand how to implement enums well enough yet.
use std::io;
fn main() {
let version = String::from("0.0.1");
let mut input = String::new();
shell(&mut input, &version);
}
fn shell(input: &mut String, version: &String) {
match io::stdin().read_line(&mut input) {
Ok(b) => {
if &input.trim() == &"ver" {
println!("{}", &version);
} else {
println!("Command '{}' Not Recognized", &input);
shell(&mut input, &version);
}
}
Err(err) => panic!("incorrect"),
}
}
The variable input itself is not mutable, it just contains a mutable reference, which is why you can't make a mutable reference to it.
However, since it is already a mutable reference, you can pass it directly to read_line, without referencing it again:
fn shell(input: &mut String, version: &String) {
match io::stdin().read_line(input) {
// already a &mut ref: ^^^^^
You could make the variable mutable, and re-borrow it:
fn shell(mut input: &mut String, version: &String) {
// ^^^
match io::stdin().read_line(&mut input) {
But this shouldn't be necessary. It only works because of Rust's auto-deref rules, which allows for things like &&&&&&T to be treated as &T in some situations. This is there for convenience because a lot of generic functions return references to their inputs and it would get messy having to dereference everything.
I am implementing a wrapper of a C library which takes callbacks and the callbacks will be implemented in Rust. Given that panicking in Rust when calling from C is undefined behavior, I want to catch any potential Rust panics before they get into C.
I have been reading about std::panic::catch_unwind. The wrapper is performance sensitive and I would prefer to avoid using types like Mutex. I would like to hold my result in an Option<i32> and set this to Some(value) in the case where there is no panic. None will indicate that the function did not execute successfully and thus, a panic must have occurred.
Is Option<i32> unwind safe? If not, under what conditions would there be a problem? Can I wrap it in std::panic::AssertUnwindSafe?
Here is an example where I used AssertUnwindSafe to wrap the entire closure.
use std::panic::{self, AssertUnwindSafe};
fn random_function_that_might_panic(a: i32) -> i32 {
if a == 42 {
panic!("did you forget a towel?");
}
a * 2
}
fn do_not_panic(a: i32) {
let mut result = None;
let unwind_state = panic::catch_unwind(AssertUnwindSafe(|| {
result = Some(random_function_that_might_panic(a)); // get result, but this could panic
}));
match unwind_state {
Ok(()) => {
match result {
Some(value) => {
println!("Result: {:?}", value);
}
None => {
// this should never happen...
println!("No result but no panic?");
}
}
}
Err(e) => {
println!("caught panic: {:?}", e);
}
}
}
fn main() {
do_not_panic(1);
do_not_panic(2);
do_not_panic(3);
do_not_panic(42);
}
(See the above on the playground.)
I could not figure out how to wrap just Option<i32> in AssertUnwindSafe, so here I wrapped the whole closure. How would I wrap just the Option<i32>?
Is Option<i32> unwind safe?
Yes. There's no reason to ask a human this question when you can ask the compiler:
fn implements<T: std::panic::UnwindSafe>() {}
fn main() {
implements::<Option<i32>>();
}
Your real question should be:
Is &mut Option<i32> unwind safe?
This is not, but you probably already knew that. I'm guessing that you got this compiler error before you added AssertUnwindSafe which tells you it isn't safe:
error[E0277]: the trait bound `&mut std::option::Option<i32>: std::panic::UnwindSafe` is not satisfied in `[closure#src/main.rs:12:44: 14:6 result:&mut std::option::Option<i32>, a:&i32]`
--> src/main.rs:12:24
|
12 | let unwind_state = panic::catch_unwind(|| {
| ^^^^^^^^^^^^^^^^^^^ the type &mut std::option::Option<i32> may not be safely transferred across an unwind boundary
|
= help: within `[closure#src/main.rs:12:44: 14:6 result:&mut std::option::Option<i32>, a:&i32]`, the trait `std::panic::UnwindSafe` is not implemented for `&mut std::option::Option<i32>`
= note: required because it appears within the type `[closure#src/main.rs:12:44: 14:6 result:&mut std::option::Option<i32>, a:&i32]`
= note: required by `std::panic::catch_unwind`
I'd write your code as this, for what it's worth:
fn do_not_panic(a: i32) {
let result = panic::catch_unwind(|| random_function_that_might_panic(a)).ok();
match result {
Some(value) => {
println!("Result: {:?}", value);
}
None => {
println!("caught panic");
}
}
}
No mutable variables, no extra nesting, no "this should never happen" comments.
See also:
The documentation for UnwindSafe
Is there a way to tell the Rust compiler to call drop on partially-initialized array elements when handling a panic?
I'm reading the documentation for File:
//..
let mut file = File::create("foo.txt")?;
//..
What is the ? in this line? I do not recall seeing it in the Rust Book before.
As you may have noticed, Rust does not have exceptions. It has panics, but their use for error-handling is discouraged (they are meant for unrecoverable errors).
In Rust, error handling uses Result. A typical example would be:
fn halves_if_even(i: i32) -> Result<i32, Error> {
if i % 2 == 0 {
Ok(i / 2)
} else {
Err(/* something */)
}
}
fn do_the_thing(i: i32) -> Result<i32, Error> {
let i = match halves_if_even(i) {
Ok(i) => i,
Err(e) => return Err(e),
};
// use `i`
}
This is great because:
when writing the code you cannot accidentally forget to deal with the error,
when reading the code you can immediately see that there is a potential for error right here.
It's less than ideal, however, in that it is very verbose. This is where the question mark operator ? comes in.
The above can be rewritten as:
fn do_the_thing(i: i32) -> Result<i32, Error> {
let i = halves_if_even(i)?;
// use `i`
}
which is much more concise.
What ? does here is equivalent to the match statement above with an addition. In short:
It unpacks the Result if OK
It returns the error if not, calling From::from on the error value to potentially convert it to another type.
It's a bit magic, but error handling needs some magic to cut down the boilerplate, and unlike exceptions it is immediately visible which function calls may or may not error out: those that are adorned with ?.
One example of the magic is that this also works for Option:
// Assume
// fn halves_if_even(i: i32) -> Option<i32>
fn do_the_thing(i: i32) -> Option<i32> {
let i = halves_if_even(i)?;
// use `i`
}
The ? operator, stabilized in Rust version 1.13.0 is powered by the (unstable) Try trait.
See also:
Is the question mark operator ? equivalent to the try! macro?
Why do try!() and ? not compile when used in a function that doesn't return Option or Result?
It is a postfix operator that unwraps Result<T, E> and Option<T> values.
If applied to Result<T, E>, it unwraps the result and gives you the inner value, propagating the error to the calling function.
let number = "42".parse::<i32>()?;
println!("{:?}", number); // 42
When applied to an Option<T>, it propagates None to the caller, leaving you the content of the Some branch to deal with.
let val = Some(42)?;
println!("{:?}", val); // 42
The ? operator can only be used in a function that returns Result or Option like so:
use std::num::ParseIntError;
fn main() -> Result<(), ParseIntError> {
let number = "42".parse::<i32>()?;
println!("{:?}", number);
Ok(())
}
It is a convenience offered by Rust, that eliminates boilerplate code and makes function's implementation simpler.
It is used for propagating errors. Sometimes we write code that might fail but we do not want to catch and handle error immediately. Your code will not be readable if you have too much code to handle the error in every place. Instead, if an error occurs, we might want to let our caller deal with it. We want errors to propagate up the call stack.
// file type is Result if "?" is not used
// file:Result<File,Error>
let mut file = File::create("foo.txt");
// file type is File if "?" is used
// file:File
let mut file = File::create("foo.txt")?;
// if an error occurs, code after this line will not be executed
// function will return the error
The behavior of ? depends on whether this function returns a successful result or an error result:
If it is a success, it unwraps the Result to get the success value inside. Value is assigned to the variable file
If the result is an error, the error is NOT assigned to the variable file. Error is returned by the function to the caller
Using ? same as this code
let mut file = match File::create("foo.txt") {
Err(why) => panic!("couldn't create {}: {}", display, why),
Ok(file) => file,
};
? also works similarly with the Option type. In a function that returns Option, you
can use ? to unwrap a value and return early in the case of None :
The existing answers are all great! I would like to give a small code snippet to demo the use of From::from() behand this question mark:
fn _parse(str: &str) -> Result<i32, &str> {
if let Ok(num) = str.parse::<i32>() {
Ok(num)
} else {
Err(str)
}
}
fn parse(str: &str) -> Result<(), String> {
let num = _parse(str)?;
println!("{}", num);
Ok(())
}
The use of ? in function parse() can be manually rewritten as:
fn parse(str: &str) -> Result<(), String> {
match _parse(str) {
Ok(n) => {
println!("{}", n);
Ok(())
}
Err(str) => Err(<String as From<&str>>::from(str)),
}
}