|
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]`][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 question mark 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 | +//! These functions are equivalent, they either return the inner value if the |
| 46 | +//! `Result` is `Ok` or panic if the `Result` is `Err` printing the inner error |
| 47 | +//! as the source. The only difference between them is that with `expect` you |
| 48 | +//! provide a panic error message to be printed alongside the source, whereas |
| 49 | +//! `unwrap` has a default message indicating only that you unwraped an `Err`. |
| 50 | +//! |
| 51 | +//! Of the two, `expect` is generally preferred since its `msg` field allows you |
| 52 | +//! to convey your intent and assumptions which makes tracking down the source |
| 53 | +//! of a panic easier. `unwrap` on the other hand can still be a good fit in |
| 54 | +//! situations where you can trivially show that a piece of code will never |
| 55 | +//! panick, such as `"127.0.0.1".parse::<std::net::IpAddr>().unwrap()` or early |
| 56 | +//! prototyping. |
| 57 | +//! |
| 58 | +//! # Common Message Styles |
| 59 | +//! |
| 60 | +//! There are two common styles for how people word `expect` messages. Using |
| 61 | +//! the message to present information to users encountering a panic |
| 62 | +//! ("expect as error message") or using the message to present information |
| 63 | +//! to developers debugging the panic ("expect as precondition"). |
| 64 | +//! |
| 65 | +//! In the former case the expect message is used to describe the error that |
| 66 | +//! has occurred which is considered a bug. Consider the following example: |
| 67 | +//! |
| 68 | +//! ```should_panic |
| 69 | +//! // Read environment variable, panic if it is not present |
| 70 | +//! let path = std::env::var("IMPORTANT_PATH").unwrap(); |
| 71 | +//! ``` |
| 72 | +//! |
| 73 | +//! In the "expect as error message" style we would use expect to describe |
| 74 | +//! that the environment variable was not set when it should have been: |
| 75 | +//! |
| 76 | +//! ```should_panic |
| 77 | +//! let path = std::env::var("IMPORTANT_PATH") |
| 78 | +//! .expect("env variable `IMPORTANT_PATH` is not set"); |
| 79 | +//! ``` |
| 80 | +//! |
| 81 | +//! In the "expect as precondition" style, we would instead describe the |
| 82 | +//! reason we _expect_ the `Result` should be `Ok`. With this style we would |
| 83 | +//! prefer to write: |
| 84 | +//! |
| 85 | +//! ```should_panic |
| 86 | +//! let path = std::env::var("IMPORTANT_PATH") |
| 87 | +//! .expect("env variable `IMPORTANT_PATH` should be set by `wrapper_script.sh`"); |
| 88 | +//! ``` |
| 89 | +//! |
| 90 | +//! The "expect as error message" style does not work as well with the |
| 91 | +//! default output of the std panic hooks, and often ends up repeating |
| 92 | +//! information that is already communicated by the source error being |
| 93 | +//! unwrapped: |
| 94 | +//! |
| 95 | +//! ```text |
| 96 | +//! thread 'main' panicked at 'env variable `IMPORTANT_PATH` is not set: NotPresent', src/main.rs:4:6 |
| 97 | +//! ``` |
| 98 | +//! |
| 99 | +//! In this example we end up mentioning that an env variable is not set, |
| 100 | +//! followed by our source message that says the env is not present, the |
| 101 | +//! only additional information we're communicating is the name of the |
| 102 | +//! environment variable being checked. |
| 103 | +//! |
| 104 | +//! The "expect as precondition" style instead focuses on source code |
| 105 | +//! readability, making it easier to understand what must have gone wrong in |
| 106 | +//! situations where panics are being used to represent bugs exclusively. |
| 107 | +//! Also, by framing our expect in terms of what "SHOULD" have happened to |
| 108 | +//! prevent the source error, we end up introducing new information that is |
| 109 | +//! independent from our source error. |
| 110 | +//! |
| 111 | +//! ```text |
| 112 | +//! thread 'main' panicked at 'env variable `IMPORTANT_PATH` should be set by `wrapper_script.sh`: NotPresent', src/main.rs:4:6 |
| 113 | +//! ``` |
| 114 | +//! |
| 115 | +//! In this example we are communicating not only the name of the |
| 116 | +//! environment variable that should have been set, but also an explanation |
| 117 | +//! for why it should have been set, and we let the source error display as |
| 118 | +//! a clear contradiction to our expectation. |
| 119 | +//! |
| 120 | +//! **Hint**: If you're having trouble remembering how to phrase |
| 121 | +//! expect-as-precondition style error messages remember to focus on the word |
| 122 | +//! "should" as in "env variable should be set by blah" or "the given binary |
| 123 | +//! should be available and executable by the current user". |
| 124 | +//! |
| 125 | +//! [`panic_any`]: crate::panic::panic_any |
| 126 | +//! [`PanicInfo`]: crate::panic::PanicInfo |
| 127 | +//! [`catch_unwind`]: crate::panic::catch_unwind |
| 128 | +//! [`resume_unwind`]: crate::panic::resume_unwind |
| 129 | +//! [`downcast`]: crate::error::Error |
| 130 | +//! [`Termination`]: crate::process::Termination |
| 131 | +//! [`Try`]: crate::ops::Try |
| 132 | +//! [panic hook]: crate::panic::set_hook |
| 133 | +//! [`set_hook`]: crate::panic::set_hook |
| 134 | +//! [`take_hook`]: crate::panic::take_hook |
| 135 | +//! [panic-handler]: <https://doc.rust-lang.org/nomicon/panic-handler.html> |
| 136 | +//! [`match`]: ../../std/keyword.match.html |
| 137 | +//! [`?`]: ../../std/result/index.html#the-question-mark-operator- |
2 | 138 |
|
3 | 139 | #![stable(feature = "rust1", since = "1.0.0")]
|
4 | 140 |
|
|
0 commit comments