|
1 |
| -//! Traits for working with Errors. |
| 1 | +//! Interfaces for working with Errors. |
| 2 | +//! |
| 3 | +//! # Error Handling In Rust |
| 4 | +//! |
| 5 | +//! The Rust language provides two complementary systems for constructing / |
| 6 | +//! representing, reporting, propagating, reacting to, and discarding errors. |
| 7 | +//! These responsibilities are collectively known as "error handling." The |
| 8 | +//! components of the first system, the panic runtime and interfaces, are most |
| 9 | +//! commonly used to represent bugs that have been detected in your program. The |
| 10 | +//! components of the second system, `Result`, the error traits, and user |
| 11 | +//! defined types, are used to represent anticipated runtime failure modes of |
| 12 | +//! your program. |
| 13 | +//! |
| 14 | +//! ## The Panic Interfaces |
| 15 | +//! |
| 16 | +//! The following are the primary interfaces of the panic system and the |
| 17 | +//! responsibilities they cover: |
| 18 | +//! |
| 19 | +//! * [`panic!`] and [`panic_any`] (Constructing, Propagated automatically) |
| 20 | +//! * [`PanicInfo`] (Reporting) |
| 21 | +//! * [`set_hook`], [`take_hook`], and [`#[panic_handler]`] (Reporting) |
| 22 | +//! * [`catch_unwind`] and [`resume_unwind`] (Discarding, Propagating) |
| 23 | +//! |
| 24 | +//! The following are the primary interfaces of the error system and the |
| 25 | +//! responsibilities they cover: |
| 26 | +//! |
| 27 | +//! * [`Result`] (Propagating, Reacting) |
| 28 | +//! * The [`Error`] trait (Reporting) |
| 29 | +//! * User defined types (Constructing / Representing) |
| 30 | +//! * `match` and [`downcast`] (Reacting) |
| 31 | +//! * The propagation operator (`?`) (Propagating) |
| 32 | +//! * The partially stable [`Try`] traits (Propagating, Constructing) |
| 33 | +//! * [`Termination`] (Reporting) |
| 34 | +//! |
| 35 | +//! ## Converting Errors into Panics |
| 36 | +//! |
| 37 | +//! The panic and error systems are not entirely distinct. Often times errors |
| 38 | +//! that are anticipated runtime failures in an API might instead represent bugs |
| 39 | +//! to a caller. For these situations the standard library provides APIs for |
| 40 | +//! constructing panics with an `Error` as it's source. |
| 41 | +//! |
| 42 | +//! * `Result::unwrap` |
| 43 | +//! * `Result::expect` |
| 44 | +//! |
| 45 | +//! TODO: how do I bridge these two sections? |
| 46 | +//! |
| 47 | +//! * unwrap is used in prototyping |
| 48 | +//! * expect is used in !prototyping (????) |
| 49 | +//! |
| 50 | +//! # Common Message Styles |
| 51 | +//! |
| 52 | +//! There are two common styles for how people word `expect` messages. Using |
| 53 | +//! the message to present information to users encountering a panic |
| 54 | +//! ("expect as error message") or using the message to present information |
| 55 | +//! to developers debugging the panic ("expect as precondition"). |
| 56 | +//! |
| 57 | +//! In the former case the expect message is used to describe the error that |
| 58 | +//! has occurred which is considered a bug. Consider the following example: |
| 59 | +//! |
| 60 | +//! ```should_panic |
| 61 | +//! // Read environment variable, panic if it is not present |
| 62 | +//! let path = std::env::var("IMPORTANT_PATH").unwrap(); |
| 63 | +//! ``` |
| 64 | +//! |
| 65 | +//! In the "expect as error message" style we would use expect to describe |
| 66 | +//! that the environment variable was not set when it should have been: |
| 67 | +//! |
| 68 | +//! ```should_panic |
| 69 | +//! let path = std::env::var("IMPORTANT_PATH") |
| 70 | +//! .expect("env variable `IMPORTANT_PATH` is not set"); |
| 71 | +//! ``` |
| 72 | +//! |
| 73 | +//! In the "expect as precondition" style, we would instead describe the |
| 74 | +//! reason we _expect_ the `Result` should be `Ok`. With this style we would |
| 75 | +//! prefer to write: |
| 76 | +//! |
| 77 | +//! ```should_panic |
| 78 | +//! let path = std::env::var("IMPORTANT_PATH") |
| 79 | +//! .expect("env variable `IMPORTANT_PATH` should be set by `wrapper_script.sh`"); |
| 80 | +//! ``` |
| 81 | +//! |
| 82 | +//! The "expect as error message" style does not work as well with the |
| 83 | +//! default output of the std panic hooks, and often ends up repeating |
| 84 | +//! information that is already communicated by the source error being |
| 85 | +//! unwrapped: |
| 86 | +//! |
| 87 | +//! ```text |
| 88 | +//! thread 'main' panicked at 'env variable `IMPORTANT_PATH` is not set: NotPresent', src/main.rs:4:6 |
| 89 | +//! ``` |
| 90 | +//! |
| 91 | +//! In this example we end up mentioning that an env variable is not set, |
| 92 | +//! followed by our source message that says the env is not present, the |
| 93 | +//! only additional information we're communicating is the name of the |
| 94 | +//! environment variable being checked. |
| 95 | +//! |
| 96 | +//! The "expect as precondition" style instead focuses on source code |
| 97 | +//! readability, making it easier to understand what must have gone wrong in |
| 98 | +//! situations where panics are being used to represent bugs exclusively. |
| 99 | +//! Also, by framing our expect in terms of what "SHOULD" have happened to |
| 100 | +//! prevent the source error, we end up introducing new information that is |
| 101 | +//! independent from our source error. |
| 102 | +//! |
| 103 | +//! ```text |
| 104 | +//! thread 'main' panicked at 'env variable `IMPORTANT_PATH` should be set by `wrapper_script.sh`: NotPresent', src/main.rs:4:6 |
| 105 | +//! ``` |
| 106 | +//! |
| 107 | +//! In this example we are communicating not only the name of the |
| 108 | +//! environment variable that should have been set, but also an explanation |
| 109 | +//! for why it should have been set, and we let the source error display as |
| 110 | +//! a clear contradiction to our expectation. |
| 111 | +//! |
| 112 | +//! For programs where panics may be user facing, either style works best |
| 113 | +//! when paired with a custom [panic hook] like the one provided by the CLI |
| 114 | +//! working group library, [`human-panic`]. This panic hook dumps the panic |
| 115 | +//! messages to a crash report file while showing users a more friendly |
| 116 | +//! "Oops, something went wrong!" message with a suggestion to send the |
| 117 | +//! crash report file back to the developers. Panic messages should be used |
| 118 | +//! to represent bugs, and the information provided back is context intended |
| 119 | +//! for the developer, not the user. |
| 120 | +//! |
| 121 | +//! [panic hook]: crate::panic::set_hook |
| 122 | +//! [`set_hook`]: crate::panic::set_hook |
| 123 | +//! [`take_hook`]: crate::panic::take_hook |
| 124 | +//! [`PanicInfo`]: crate::panic::PanicInfo |
| 125 | +//! [`panic_any`]: crate::panic::panic_any |
| 126 | +//! [`#[panic_handler]`]: https://doc.rust-lang.org/nomicon/panic-handler.html |
| 127 | +//! [`catch_unwind`]: crate::panic::catch_unwind |
| 128 | +//! [`resume_unwind`]: crate::panic::resume_unwind |
| 129 | +//! [`Termination`]: crate::process::Termination |
| 130 | +//! [`Try`]: crate::ops::Try |
| 131 | +//! [`downcast`]: crate::error::Error |
| 132 | +//! [`human-panic`]: https://docs.rs/human-panic |
2 | 133 |
|
3 | 134 | #![stable(feature = "rust1", since = "1.0.0")]
|
4 | 135 |
|
|
0 commit comments