3 releases
0.1.2 | Sep 12, 2021 |
---|---|
0.1.1 | Jul 18, 2020 |
0.1.0 | Sep 24, 2019 |
#370 in Command-line interface
1,550 downloads per month
Used in fewer than 12 crates
8KB
main_error
Print errors with Display
instead of Debug
when using ?
in main()
. For example:
use main_error::MainError;
fn main() -> Result<(), MainError> {
// This prints
// "Error: invalid digit found in string"
// instead of (if you used `Result<(), Box<dyn Error>>` or similar)
// "ParseIntError { kind: InvalidDigit }".
let number: i32 = "not a number".parse()?;
Ok(())
}
For more info, see:
- Package information on crates.io
- Documentation on Docs.rs
- Usage examples in the repo
lib.rs
:
Print errors with [Display
] instead of [Debug
] when using ?
in main()
.
Use by returning [MainError
] as the error type from main()
.
Example:
use main_error::MainError;
fn main() -> Result<(), MainError> {
// This prints
// "Error: invalid digit found in string"
// instead of (if you used `Result<(), Box<dyn Error>>` or similar)
// "ParseIntError { kind: InvalidDigit }".
let number: i32 = "not a number".parse()?;
Ok(())
}
For convenience, you can also use the [MainResult
] type.
See below for more details.
The Issue
Since Rust 1.26, main()
function can return a Result<T, E>
.
This enables the use of ?
for convenient error handling in small programs and quick examples (RFC).
Unfortunately, the error is printed via [Debug
] (hardcoded in the standard library, search for "Error:"),
which gives not very pretty or human-friendly output.
For example, this program:
# use std::num::ParseIntError;
fn main() -> Result<(), ParseIntError> {
let num: i32 = "not a number".parse()?;
// ...
# Ok(())
}
will print
Error: ParseIntError { kind: InvalidDigit }
Solution
This crate provides [MainError
] as a drop-in replacement for the error type E
in your main
's Result<T, E>
.
It prints the error via [Display
] instead of [Debug
], which yields a nicer error message.
For example, the program above can be changed to
use main_error::MainError;
fn main() -> Result<(), MainError> {
let _: i32 = "not a number".parse()?;
// ...
# Ok(())
}
and now prints:
Error: invalid digit found in string
Details and Drawbacks
- [
MainError
] stores the original error asBox<dyn Error>
. This incurs one allocation (on conversion) and one virtual call (on printing). Since there can be exactly one error like this before the program ends, this cost is insignificant. - [
MainError
] implements [From
] for all types that can be converted into aBox<dyn Error>
.- This allows it to be used in place of any type that implements the [
Error
] trait (see example above). - It can also be used in place of any type that can be converted to a
Box<dyn Error>
, e.g.,String
.
- This allows it to be used in place of any type that implements the [
- [
MainError
] does not implement the [Error
] trait itself. Reasons:- It's not necessary, because the standard library only requires
E: Debug
formain() -> Result<T, E>
. - You should only be using
MainError
formain()
anyway, whereas theError
trait is more for interoparability between libraries. - One simply cannot implement
Error
forMainError
, because this would create an overlappingimpl
.
Explanation:MainError
can be converted from aT: Into<Box<dyn Error>>
.Into<Box<dyn Error>>
is implemented forE: Error
itself.- If
MainError
would implementError
, it could be converted from itself. - This collides with the reflexive
impl<T> From<T> for T
in core.
- It's not necessary, because the standard library only requires
- [
MainError
] implements [Debug
] in terms of [Display
] of the underlying error. This is hacky, but unfortunately [Debug
] as the output for themain
error case is stable now. The"Error: "
part at the beginning of the output comes from the standard library, thus it cannot be changed.