From 2b9f0dc4d8d551effadc7fd920bfcaa3d0e8e9f3 Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Tue, 13 Sep 2022 11:53:08 -0400 Subject: [PATCH] Regenerate chapter 9 --- nostarch/chapter09.md | 669 ++---------------------------------------- 1 file changed, 19 insertions(+), 650 deletions(-) diff --git a/nostarch/chapter09.md b/nostarch/chapter09.md index 356c1e7cf..693081d94 100644 --- a/nostarch/chapter09.md +++ b/nostarch/chapter09.md @@ -1,3 +1,8 @@ + [TOC] @@ -37,43 +42,31 @@ print a failure message, unwind, clean up the stack, and quit. Via an environment variable, you can also have Rust display the call stack when a panic occurs to make it easier to track down the source of the panic. - -Unmatched: BoxType - > ### Unwinding the Stack or Aborting in Response to a Panic - - +> > By default, when a panic occurs the program starts *unwinding*, which means Rust walks back up the stack and cleans up the data from each function it encounters. However, walking back and cleaning up is a lot of work. Rust, therefore, allows you to choose the alternative of immediately *aborting*, which ends the program without cleaning up. - - +> > Memory that the program was using will then need to be cleaned up by the operating system. If in your project you need to make the resultant binary as small as possible, you can switch from unwinding to aborting upon a panic by adding `panic = 'abort'` to the appropriate `[profile]` sections in your *Cargo.toml* file. For example, if you want to abort on panic in release mode, add this: - - -Unmatched: BoxCode - -Unmatched: BoxCode - Let’s try calling `panic!` in a simple program: +> +> ``` +> [profile.release] +> panic = 'abort' +Let’s try calling `panic!` in a simple program: Filename: src/main.rs ``` fn main() { -``` - -``` panic!("crash and burn"); -``` - -``` } ``` @@ -81,13 +74,7 @@ When you run the program, you’ll see something like this: ``` thread 'main' panicked at 'crash and burn', src/main.rs:2:5 -``` - -``` note: run with `RUST_BACKTRACE=1` environment variable to display -``` - -``` a backtrace ``` @@ -113,21 +100,9 @@ Filename: src/main.rs ``` fn main() { -``` - -``` let v = vec![1, 2, 3]; -``` -``` - -``` - -``` v[99]; -``` - -``` } ``` @@ -154,19 +129,13 @@ continue. Let’s try it and see: ``` thread 'main' panicked at 'index out of bounds: the len is 3 but the index is -``` - -``` 99', src/main.rs:4:5 -``` - -``` note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace ``` This error points at line 4 of our *main.rs* where we attempt to access `index`. -The `note``:` line tells us that we can set the `RUST_BACKTRACE` environment +The `note:` line tells us that we can set the `RUST_BACKTRACE` environment variable to get a backtrace of exactly what happened to cause the error. A *backtrace* is a list of all the functions that have been called to get to this point. Backtraces in Rust work as they do in other languages: the key to @@ -180,113 +149,32 @@ Listing 9-2 shows output similar to what you’ll see. ``` $ RUST_BACKTRACE=1 cargo run -``` - -``` thread 'main' panicked at 'index out of bounds: the len is 3 but the index is -``` - -``` 99', src/main.rs:4:5 -``` - -``` stack backtrace: -``` - -``` 0: rust_begin_unwind -``` - -``` at /rustc/e092d0b6b43f2de967af0887873151bb1c0b18d3/library/std -``` - -``` /src/panicking.rs:584:5 -``` - -``` 1: core::panicking::panic_fmt -``` - -``` at /rustc/e092d0b6b43f2de967af0887873151bb1c0b18d3/library/core -``` - -``` /src/panicking.rs:142:14 -``` - -``` 2: core::panicking::panic_bounds_check -``` - -``` at /rustc/e092d0b6b43f2de967af0887873151bb1c0b18d3/library/core -``` - -``` /src/panicking.rs:84:5 -``` - -``` 3: >::index -``` - -``` at /rustc/e092d0b6b43f2de967af0887873151bb1c0b18d3/library/core -``` - -``` /src/slice/index.rs:242:10 -``` - -``` 4: core::slice::index:: for [T]>::index -``` - -``` at /rustc/e092d0b6b43f2de967af0887873151bb1c0b18d3/library/core -``` - -``` /src/slice/index.rs:18:9 -``` - -``` 5: as core::ops::index::Index>::index -``` - -``` at /rustc/e092d0b6b43f2de967af0887873151bb1c0b18d3/library/alloc -``` - -``` /src/vec/mod.rs:2591:9 -``` - -``` 6: panic::main -``` - -``` at ./src/main.rs:4:5 -``` - -``` 7: core::ops::function::FnOnce::call_once -``` - -``` at /rustc/e092d0b6b43f2de967af0887873151bb1c0b18d3/library/core -``` - -``` /src/ops/function.rs:248:5 -``` - -``` note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace. ``` @@ -326,17 +214,8 @@ Recall from “Handling Potential Failure with Result” on page XX that the ``` enum Result { -``` - -``` Ok(T), -``` - -``` Err(E), -``` - -``` } ``` @@ -356,21 +235,9 @@ Filename: src/main.rs ``` use std::fs::File; -``` -``` - -``` - -``` fn main() { -``` - -``` let greeting_file_result = File::open("hello.txt"); -``` - -``` } ``` @@ -402,49 +269,16 @@ Filename: src/main.rs ``` use std::fs::File; -``` -``` - -``` - -``` fn main() { -``` - -``` let greeting_file_result = File::open("hello.txt"); -``` -``` - -``` - -``` let greeting_file = match greeting_file_result { -``` - -``` Ok(file) => file, -``` - -``` Err(error) => { -``` - -``` panic!("Problem opening the file: {:?}", error); -``` - -``` } -``` - -``` }; -``` - -``` } ``` @@ -467,13 +301,7 @@ code, we’ll see the following output from the `panic!` macro: ``` thread 'main' panicked at 'Problem opening the file: Os { code: -``` - -``` 2, kind: NotFound, message: "No such file or directory" }', -``` - -``` src/main.rs:8:23 ``` @@ -493,109 +321,31 @@ Filename: src/main.rs ``` use std::fs::File; -``` - -``` use std::io::ErrorKind; -``` -``` - -``` - -``` fn main() { -``` - -``` let greeting_file_result = File::open("hello.txt"); -``` -``` - -``` - -``` let greeting_file = match greeting_file_result { -``` - -``` Ok(file) => file, -``` - -``` Err(error) => match error.kind() { -``` - -``` ErrorKind::NotFound => { -``` - -``` match File::create("hello.txt") { -``` - -``` Ok(fc) => fc, -``` - -``` Err(e) => panic!( -``` - -``` "Problem creating the file: {:?}", -``` - -``` e -``` - -``` ), -``` - -``` } -``` - -``` } -``` - -``` other_error => { -``` - -``` panic!( -``` - -``` "Problem opening the file: {:?}", -``` - -``` other_error -``` - -``` ); -``` - -``` } -``` - -``` }, -``` - -``` }; -``` - -``` } ``` @@ -630,61 +380,19 @@ For example, here’s another way to write the same logic as shown in Listing ``` // src/main.rs -``` - -``` use std::fs::File; -``` - -``` use std::io::ErrorKind; -``` -``` - -``` - -``` fn main() { -``` - -``` let greeting_file = File::open("hello.txt").unwrap_or_else(|error| { -``` - -``` if error.kind() == ErrorKind::NotFound { -``` - -``` File::create("hello.txt").unwrap_or_else(|error| { -``` - -``` panic!("Problem creating the file: {:?}", error); -``` - -``` }) -``` - -``` } else { -``` - -``` panic!("Problem opening the file: {:?}", error); -``` - -``` } -``` - -``` }); -``` - -``` } ``` @@ -708,21 +416,9 @@ Filename: src/main.rs ``` use std::fs::File; -``` -``` - -``` - -``` fn main() { -``` - -``` let greeting_file = File::open("hello.txt").unwrap(); -``` - -``` } ``` @@ -731,13 +427,7 @@ the `panic!` call that the `unwrap` method makes: ``` thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: Os { -``` - -``` code: 2, kind: NotFound, message: "No such file or directory" }', -``` - -``` src/main.rs:4:49 ``` @@ -750,25 +440,10 @@ Filename: src/main.rs ``` use std::fs::File; -``` -``` - -``` - -``` fn main() { -``` - -``` let greeting_file = File::open("hello.txt") -``` - -``` .expect("hello.txt should be included in this project"); -``` - -``` } ``` @@ -779,13 +454,7 @@ will be the parameter that we pass to `expect`, rather than the default ``` thread 'main' panicked at 'hello.txt should be included in this project: Os { -``` - -``` code: 2, kind: NotFound, message: "No such file or directory" }', -``` - -``` src/main.rs:5:10 ``` @@ -811,73 +480,22 @@ Filename: src/main.rs ``` use std::fs::File; -``` - -``` use std::io::{self, Read}; -``` -``` - -``` - -``` 1 fn read_username_from_file() -> Result { -``` - -``` 2 let username_file_result = File::open("hello.txt"); -``` -``` - -``` - -``` 3 let mut username_file = match username_file_result { -``` - -``` 4 Ok(file) => file, -``` - -``` 5 Err(e) => return Err(e), -``` - -``` }; -``` -``` - -``` - -``` 6 let mut username = String::new(); -``` -``` - -``` - -``` 7 match username_file.read_to_string(&mut username) { -``` - -``` 8 Ok(_) => Ok(username), -``` - -``` 9 Err(e) => Err(e), -``` - -``` } -``` - -``` } ``` @@ -944,37 +562,13 @@ Filename: src/main.rs ``` use std::fs::File; -``` - -``` use std::io::{self, Read}; -``` -``` - -``` - -``` fn read_username_from_file() -> Result { -``` - -``` let mut username_file = File::open("hello.txt")?; -``` - -``` let mut username = String::new(); -``` - -``` username_file.read_to_string(&mut username)?; -``` - -``` Ok(username) -``` - -``` } ``` @@ -1019,41 +613,14 @@ Filename: src/main.rs ``` use std::fs::File; -``` - -``` use std::io::{self, Read}; -``` -``` - -``` - -``` fn read_username_from_file() -> Result { -``` - -``` let mut username = String::new(); -``` -``` - -``` - -``` File::open("hello.txt")?.read_to_string(&mut username)?; -``` -``` - -``` - -``` Ok(username) -``` - -``` } ``` @@ -1074,25 +641,10 @@ Filename: src/main.rs ``` use std::fs; -``` - -``` use std::io; -``` -``` - -``` - -``` fn read_username_from_file() -> Result { -``` - -``` fs::read_to_string("hello.txt") -``` - -``` } ``` @@ -1123,21 +675,9 @@ Filename: src/main.rs ``` use std::fs::File; -``` -``` - -``` - -``` fn main() { -``` - -``` let greeting_file = File::open("hello.txt")?; -``` - -``` } ``` @@ -1151,53 +691,17 @@ message: ``` error[E0277]: the `?` operator can only be used in a function that returns -``` - -``` `Result` or `Option` (or another type that implements `FromResidual`) -``` - -``` --> src/main.rs:4:48 -``` - -``` | -``` - -``` 3 | / fn main() { -``` - -``` 4 | | let greeting_file = File::open("hello.txt")?; -``` - -``` | | ^ cannot use the `?` -``` - -``` operator in a function that returns `()` -``` - -``` 5 | | } -``` - -``` | |_- this function should return `Result` or `Option` to accept `?` -``` - -``` | -``` - -``` = help: the trait `FromResidual>` is not -``` - -``` implemented for `()` ``` @@ -1223,13 +727,7 @@ given text. ``` fn last_char_of_first_line(text: &str) -> Option { -``` - -``` text.lines().next()?.chars().last() -``` - -``` } ``` @@ -1273,35 +771,16 @@ from Listing 9-10, but we’ve changed the return type of `main` to be `Result<(), Box>` and added a return value `Ok(())` to the end. This code will now compile. +Filename: src/main.rs + ``` use std::error::Error; -``` - -``` use std::fs::File; -``` -``` - -``` - -``` fn main() -> Result<(), Box> { -``` - -``` let greeting_file = File::open("hello.txt")?; -``` -``` - -``` - -``` Ok(()) -``` - -``` } ``` @@ -1384,21 +863,9 @@ that you’ll never have an `Err` variant, it’s perfectly acceptable to call ``` use std::net::IpAddr; -``` -``` - -``` - -``` let home: IpAddr = "127.0.0.1" -``` - -``` .parse() -``` - -``` .expect("Hardcoded IP address should be valid"); ``` @@ -1489,67 +956,24 @@ One way to do this would be to parse the guess as an `i32` instead of only a `u32` to allow potentially negative numbers, and then add a check for the number being in range, like so: +Filename: src/main.rs + ``` loop { -``` - -``` --snip-- -``` -``` - -``` - -``` let guess: i32 = match guess.trim().parse() { -``` - -``` Ok(num) => num, -``` - -``` Err(_) => continue, -``` - -``` }; -``` -``` - -``` - -``` if guess < 1 || guess > 100 { -``` - -``` println!("The secret number will be between 1 and 100."); -``` - -``` continue; -``` - -``` } -``` -``` - -``` - -``` match guess.cmp(&secret_number) { -``` - -``` --snip-- -``` - -``` } ``` @@ -1571,83 +995,28 @@ confidently use the values they receive. Listing 9-13 shows one way to define a `Guess` type that will only create an instance of `Guess` if the `new` function receives a value between 1 and 100. +Filename: src/lib.rs + ``` 1 pub struct Guess { -``` - -``` value: i32, -``` - -``` } -``` -``` - -``` - -``` impl Guess { -``` - -``` 2 pub fn new(value: i32) -> Guess { -``` - -``` 3 if value < 1 || value > 100 { -``` - -``` 4 panic!( -``` - -``` "Guess value must be between 1 and 100, got {}.", -``` - -``` value -``` - -``` ); -``` - -``` } -``` -``` - -``` - -``` 5 Guess { value } -``` - -``` } -``` -``` - -``` - -``` 6 pub fn value(&self) -> i32 { -``` - -``` self.value -``` - -``` } -``` - -``` } ```