Skip to content

Commit 41e7f45

Browse files
committed
Guide: improve error handling
1 parent cd54321 commit 41e7f45

File tree

1 file changed

+131
-49
lines changed

1 file changed

+131
-49
lines changed

src/doc/guide.md

Lines changed: 131 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1190,25 +1190,31 @@ can only be _one_ of `Less`, `Equal`, or `Greater` at any given time. Here's
11901190
an example:
11911191

11921192
```rust
1193-
let x = 5i;
1194-
let y = 10i;
1193+
fn cmp(a: int, b: int) -> Ordering {
1194+
if a < b { Less }
1195+
else if a > b { Greater }
1196+
else { Equal }
1197+
}
1198+
1199+
fn main() {
1200+
let x = 5i;
1201+
let y = 10i;
11951202

1196-
let ordering = x.cmp(&y);
1203+
let ordering = cmp(x, y);
11971204

1198-
if ordering == Less {
1199-
println!("less");
1200-
} else if ordering == Greater {
1201-
println!("greater");
1202-
} else if ordering == Equal {
1203-
println!("equal");
1205+
if ordering == Less {
1206+
println!("less");
1207+
} else if ordering == Greater {
1208+
println!("greater");
1209+
} else if ordering == Equal {
1210+
println!("equal");
1211+
}
12041212
}
12051213
```
12061214

1207-
`cmp` is a function that compares two things, and returns an `Ordering`. The
1208-
call looks a little bit strange: rather than `cmp(x, y)`, we say `x.cmp(&y)`.
1209-
We haven't covered methods and references yet, so it should look a little bit
1210-
foreign. Right now, just pretend it says `cmp(x, y)`, and we'll get to those
1211-
details soon.
1215+
`cmp` is a function that compares two things, and returns an `Ordering`. We
1216+
return either `Less`, `Greater`, or `Equal`, depending on if the two values
1217+
are greater, less, or equal.
12121218

12131219
The `ordering` variable has the type `Ordering`, and so contains one of the
12141220
three values. We can then do a bunch of `if`/`else` comparisons to check
@@ -1219,12 +1225,12 @@ that not only makes them nicer to read, but also makes sure that you never
12191225
miss a case. Before we get to that, though, let's talk about another kind of
12201226
enum: one with values.
12211227

1222-
This enum has two variants, one of which has a value.:
1228+
This enum has two variants, one of which has a value:
12231229

1224-
```
1230+
```{rust}
12251231
enum OptionalInt {
12261232
Value(int),
1227-
Missing
1233+
Missing,
12281234
}
12291235
12301236
fn main() {
@@ -1308,30 +1314,46 @@ for every possible value of `x`, and so our program will now compile.
13081314
section on enums?
13091315

13101316
```{rust}
1311-
let x = 5i;
1312-
let y = 10i;
1317+
fn cmp(a: int, b: int) -> Ordering {
1318+
if a < b { Less }
1319+
else if a > b { Greater }
1320+
else { Equal }
1321+
}
1322+
1323+
fn main() {
1324+
let x = 5i;
1325+
let y = 10i;
13131326
1314-
let ordering = x.cmp(&y);
1327+
let ordering = cmp(x, y);
13151328
1316-
if ordering == Less {
1317-
println!("less");
1318-
} else if ordering == Greater {
1319-
println!("greater");
1320-
} else if ordering == Equal {
1321-
println!("equal");
1329+
if ordering == Less {
1330+
println!("less");
1331+
} else if ordering == Greater {
1332+
println!("greater");
1333+
} else if ordering == Equal {
1334+
println!("equal");
1335+
}
13221336
}
13231337
```
13241338

13251339
We can re-write this as a `match`:
13261340

13271341
```{rust}
1328-
let x = 5i;
1329-
let y = 10i;
1342+
fn cmp(a: int, b: int) -> Ordering {
1343+
if a < b { Less }
1344+
else if a > b { Greater }
1345+
else { Equal }
1346+
}
13301347
1331-
match x.cmp(&y) {
1332-
Less => println!("less"),
1333-
Greater => println!("greater"),
1334-
Equal => println!("equal"),
1348+
fn main() {
1349+
let x = 5i;
1350+
let y = 10i;
1351+
1352+
match cmp(x, y) {
1353+
Less => println!("less"),
1354+
Greater => println!("greater"),
1355+
Equal => println!("equal"),
1356+
}
13351357
}
13361358
```
13371359

@@ -1344,17 +1366,25 @@ make sure to cover all of our bases.
13441366
`match` is also an expression, which means we can use it on the right hand side
13451367
of a `let` binding. We could also implement the previous line like this:
13461368

1347-
```
1348-
let x = 5i;
1349-
let y = 10i;
1369+
```{rust}
1370+
fn cmp(a: int, b: int) -> Ordering {
1371+
if a < b { Less }
1372+
else if a > b { Greater }
1373+
else { Equal }
1374+
}
13501375
1351-
let result = match x.cmp(&y) {
1352-
Less => "less",
1353-
Greater => "greater",
1354-
Equal => "equal",
1355-
};
1376+
fn main() {
1377+
let x = 5i;
1378+
let y = 10i;
13561379
1357-
println!("{}", result);
1380+
let result = match cmp(x, y) {
1381+
Less => "less",
1382+
Greater => "greater",
1383+
Equal => "equal",
1384+
};
1385+
1386+
println!("{}", result);
1387+
}
13581388
```
13591389

13601390
In this case, it doesn't make a lot of sense, as we are just making a temporary
@@ -1574,16 +1604,68 @@ a full line of input. Nice and easy.
15741604
.ok().expect("Failed to read line");
15751605
```
15761606

1577-
Here's the thing: reading a line from standard input could fail. For example,
1578-
if this program isn't running in a terminal, but is running as part of a cron
1579-
job, or some other context where there's no standard input. So Rust expects us
1580-
to handle this case. Given that we plan on always running this program in a
1581-
terminal, we use the `ok()` method to tell Rust that we're expecting everything
1582-
to be just peachy, and the `expect()` method on that result to give an error
1583-
message if our expectation goes wrong.
1607+
Do you remember this code?
1608+
1609+
```
1610+
enum OptionalInt {
1611+
Value(int),
1612+
Missing,
1613+
}
1614+
1615+
fn main() {
1616+
let x = Value(5);
1617+
let y = Missing;
1618+
1619+
match x {
1620+
Value(n) => println!("x is {:d}", n),
1621+
Missing => println!("x is missing!"),
1622+
}
1623+
1624+
match y {
1625+
Value(n) => println!("y is {:d}", n),
1626+
Missing => println!("y is missing!"),
1627+
}
1628+
}
1629+
```
1630+
1631+
We had to match each time, to see if we had a value or not. In this case,
1632+
though, we _know_ that `x` has a `Value`. But `match` forces us to handle
1633+
the `missing` case. This is what we want 99% of the time, but sometimes, we
1634+
know better than the compiler.
1635+
1636+
Likewise, `read_line()` does not return a line of input. It _might_ return a
1637+
line of input. It might also fail to do so. This could happen if our program
1638+
isn't running in a terminal, but as part of a cron job, or some other context
1639+
where there's no standard input. Because of this, `read_line` returns a type
1640+
very similar to our `OptionalInt`: an `IoResult<T>`. We haven't talked about
1641+
`IoResult<T>` yet because it is the **generic** form of our `OptionalInt`.
1642+
Until then, you can think of it as being the same thing, just for any type, not
1643+
just `int`s.
1644+
1645+
Rust provides a method on these `IoResult<T>`s called `ok()`, which does the
1646+
same thing as our `match` statement, but assuming that we have a valid value.
1647+
If we don't, it will terminate our program. In this case, if we can't get
1648+
input, our program doesn't work, so we're okay with that. In most cases, we
1649+
would want to handle the error case explicitly. The result of `ok()` has a
1650+
method, `expect()`, which allows us to give an error message if this crash
1651+
happens.
15841652

15851653
We will cover the exact details of how all of this works later in the Guide.
1586-
For now, this is all you need.
1654+
For now, this gives you enough of a basic understanding to work with.
1655+
1656+
Back to the code we were working on! Here's a refresher:
1657+
1658+
```{rust,ignore}
1659+
use std::io;
1660+
1661+
fn main() {
1662+
println!("Type something!");
1663+
1664+
let input = io::stdin().read_line().ok().expect("Failed to read line");
1665+
1666+
println!("{}", input);
1667+
}
1668+
```
15871669

15881670
With long lines like this, Rust gives you some flexibility with the whitespace.
15891671
We _could_ write the example like this:

0 commit comments

Comments
 (0)