]> git.lizzy.rs Git - rust.git/blob - src/doc/trpl/error-handling.md
Rollup merge of #21357 - kimroen:patch-1, r=sanxiyn
[rust.git] / src / doc / trpl / error-handling.md
1 % Error Handling
2
3 > The best-laid plans of mice and men  
4 > Often go awry
5 >
6 > "Tae a Moose", Robert Burns
7
8 Sometimes, things just go wrong. It's important to have a plan for when the
9 inevitable happens. Rust has rich support for handling errors that may (let's
10 be honest: will) occur in your programs.
11
12 There are two main kinds of errors that can occur in your programs: failures,
13 and panics. Let's talk about the difference between the two, and then discuss
14 how to handle each. Then, we'll discuss upgrading failures to panics.
15
16 # Failure vs. Panic
17
18 Rust uses two terms to differentiate between two forms of error: failure, and
19 panic. A *failure* is an error that can be recovered from in some way. A
20 *panic* is an error that cannot be recovered from.
21
22 What do we mean by "recover"? Well, in most cases, the possibility of an error
23 is expected. For example, consider the `from_str` function:
24
25 ```{rust,ignore}
26 from_str("5");
27 ```
28
29 This function takes a string argument and converts it into another type. But
30 because it's a string, you can't be sure that the conversion actually works.
31 For example, what should this convert to?
32
33 ```{rust,ignore}
34 from_str("hello5world");
35 ```
36
37 This won't work. So we know that this function will only work properly for some
38 inputs. It's expected behavior. We call this kind of error a *failure*.
39
40 On the other hand, sometimes, there are errors that are unexpected, or which
41 we cannot recover from. A classic example is an `assert!`:
42
43 ```{rust,ignore}
44 assert!(x == 5);
45 ```
46
47 We use `assert!` to declare that something is true. If it's not true, something
48 is very wrong. Wrong enough that we can't continue with things in the current
49 state. Another example is using the `unreachable!()` macro:
50
51 ```{rust,ignore}
52 enum Event {
53     NewRelease,
54 }
55
56 fn probability(_: &Event) -> f64 {
57     // real implementation would be more complex, of course
58     0.95
59 }
60
61 fn descriptive_probability(event: Event) -> &'static str {
62     match probability(&event) {
63         1.00 => "certain",
64         0.00 => "impossible",
65         0.00 ... 0.25 => "very unlikely",
66         0.25 ... 0.50 => "unlikely",
67         0.50 ... 0.75 => "likely",
68         0.75 ... 1.00 => "very likely",
69     }
70 }
71
72 fn main() {
73     std::io::println(descriptive_probability(NewRelease));
74 }
75 ```
76
77 This will give us an error:
78
79 ```text
80 error: non-exhaustive patterns: `_` not covered [E0004]
81 ```
82
83 While we know that we've covered all possible cases, Rust can't tell. It
84 doesn't know that probability is between 0.0 and 1.0. So we add another case:
85
86 ```rust
87 use Event::NewRelease;
88
89 enum Event {
90     NewRelease,
91 }
92
93 fn probability(_: &Event) -> f64 {
94     // real implementation would be more complex, of course
95     0.95
96 }
97
98 fn descriptive_probability(event: Event) -> &'static str {
99     match probability(&event) {
100         1.00 => "certain",
101         0.00 => "impossible",
102         0.00 ... 0.25 => "very unlikely",
103         0.25 ... 0.50 => "unlikely",
104         0.50 ... 0.75 => "likely",
105         0.75 ... 1.00 => "very likely",
106         _ => unreachable!()
107     }
108 }
109
110 fn main() {
111     println!("{}", descriptive_probability(NewRelease));
112 }
113 ```
114
115 We shouldn't ever hit the `_` case, so we use the `unreachable!()` macro to
116 indicate this. `unreachable!()` gives a different kind of error than `Result`.
117 Rust calls these sorts of errors *panics*.
118
119 # Handling errors with `Option` and `Result`
120
121 The simplest way to indicate that a function may fail is to use the `Option<T>`
122 type. Remember our `from_str()` example? Here's its type signature:
123
124 ```{rust,ignore}
125 pub fn from_str<A: FromStr>(s: &str) -> Option<A>
126 ```
127
128 `from_str()` returns an `Option<A>`. If the conversion succeeds, it will return
129 `Some(value)`, and if it fails, it will return `None`.
130
131 This is appropriate for the simplest of cases, but doesn't give us a lot of
132 information in the failure case. What if we wanted to know _why_ the conversion
133 failed? For this, we can use the `Result<T, E>` type. It looks like this:
134
135 ```rust
136 enum Result<T, E> {
137    Ok(T),
138    Err(E)
139 }
140 ```
141
142 This enum is provided by Rust itself, so you don't need to define it to use it
143 in your code. The `Ok(T)` variant represents a success, and the `Err(E)` variant
144 represents a failure. Returning a `Result` instead of an `Option` is recommended
145 for all but the most trivial of situations.
146
147 Here's an example of using `Result`:
148
149 ```rust
150 #[derive(Show)]
151 enum Version { Version1, Version2 }
152
153 #[derive(Show)]
154 enum ParseError { InvalidHeaderLength, InvalidVersion }
155
156 fn parse_version(header: &[u8]) -> Result<Version, ParseError> {
157     if header.len() < 1 {
158         return Err(ParseError::InvalidHeaderLength);
159     }
160     match header[0] {
161         1 => Ok(Version::Version1),
162         2 => Ok(Version::Version2),
163         _ => Err(ParseError::InvalidVersion)
164     }
165 }
166
167 let version = parse_version(&[1, 2, 3, 4]);
168 match version {
169     Ok(v) => {
170         println!("working with version: {:?}", v);
171     }
172     Err(e) => {
173         println!("error parsing header: {:?}", e);
174     }
175 }
176 ```
177
178 This function makes use of an enum, `ParseError`, to enumerate the various
179 errors that can occur.
180
181 # Non-recoverable errors with `panic!`
182
183 In the case of an error that is unexpected and not recoverable, the `panic!`
184 macro will induce a panic. This will crash the current thread, and give an error:
185
186 ```{rust,ignore}
187 panic!("boom");
188 ```
189
190 gives
191
192 ```text
193 thread '<main>' panicked at 'boom', hello.rs:2
194 ```
195
196 when you run it.
197
198 Because these kinds of situations are relatively rare, use panics sparingly.
199
200 # Upgrading failures to panics
201
202 In certain circumstances, even though a function may fail, we may want to treat
203 it as a panic instead. For example, `io::stdin().read_line()` returns an
204 `IoResult<String>`, a form of `Result`, when there is an error reading the
205 line. This allows us to handle and possibly recover from this sort of error.
206
207 If we don't want to handle this error, and would rather just abort the program,
208 we can use the `unwrap()` method:
209
210 ```{rust,ignore}
211 io::stdin().read_line().unwrap();
212 ```
213
214 `unwrap()` will `panic!` if the `Option` is `None`. This basically says "Give
215 me the value, and if something goes wrong, just crash." This is less reliable
216 than matching the error and attempting to recover, but is also significantly
217 shorter. Sometimes, just crashing is appropriate.
218
219 There's another way of doing this that's a bit nicer than `unwrap()`:
220
221 ```{rust,ignore}
222 let input = io::stdin().read_line()
223                        .ok()
224                        .expect("Failed to read line");
225 ```
226 `ok()` converts the `IoResult` into an `Option`, and `expect()` does the same
227 thing as `unwrap()`, but takes a message. This message is passed along to the
228 underlying `panic!`, providing a better error message if the code errors.