diff --git a/2018-edition/src/ch09-02-recoverable-errors-with-result.md b/2018-edition/src/ch09-02-recoverable-errors-with-result.md index e541ef1e1..a36ebaf9e 100644 --- a/2018-edition/src/ch09-02-recoverable-errors-with-result.md +++ b/2018-edition/src/ch09-02-recoverable-errors-with-result.md @@ -307,19 +307,22 @@ fn read_username_from_file() -> Result { Listing 9-6: A function that returns errors to the calling code using `match` -Let’s look at the return type of the function first: `Result`. This means the function is returning a value of the type -`Result` where the generic parameter `T` has been filled in with the -concrete type `String`, and the generic type `E` has been filled in with the -concrete type `io::Error`. If this function succeeds without any problems, the -code that calls this function will receive an `Ok` value that holds a -`String`—the username that this function read from the file. If this function -encounters any problems, the code that calls this function will receive an -`Err` value that holds an instance of `io::Error` that contains more -information about what the problems were. We chose `io::Error` as the return -type of this function because that happens to be the type of the error value -returned from both of the operations we’re calling in this function’s body that -might fail: the `File::open` function and the `read_to_string` method. +This function can be written in a much shorter way, but we're going to start by +doing a lot of it manually in order to explore error handling; at the end, +we'll show the easy way. Let’s look at the return type of the function first: +`Result`. This means the function is returning a value of +the type `Result` where the generic parameter `T` has been filled in +with the concrete type `String`, and the generic type `E` has been filled in +with the concrete type `io::Error`. If this function succeeds without any +problems, the code that calls this function will receive an `Ok` value that +holds a `String`—the username that this function read from the file. If this +function encounters any problems, the code that calls this function will +receive an `Err` value that holds an instance of `io::Error` that contains +more information about what the problems were. We chose `io::Error` as the +return type of this function because that happens to be the type of the error +value returned from both of the operations we’re calling in this function’s +body that might fail: the `File::open` function and the `read_to_string` +method. The body of the function starts by calling the `File::open` function. Then we handle the `Result` value returned with a `match` similar to the `match` in @@ -431,6 +434,30 @@ username in `s` when both `File::open` and `read_to_string` succeed rather than returning errors. The functionality is again the same as in Listing 9-6 and Listing 9-7; this is just a different, more ergonomic way to write it. +Speaking of different ways to write this function, there's a way to make this even +shorter: + +Filename: src/main.rs + +```rust +use std::io; +use std::io::Read; +use std::fs; + +fn read_username_from_file() -> Result { + fs::read_to_string("hello.txt") +} +``` + +Listing 9-9: Using `fs::read_to_string` + +Reading a file into a string is a fairly common operation, and so Rust +provides a convenience function called `fs::read_to_string` that will +open the file, create a new `String`, read the contents of the file, +and put the contents into that `String`, and then return it. Of course, +this doesn't give us the opportunity to show off all of this error handling, +so we did it the hard way at first. + #### The `?` Operator Can Only Be Used in Functions That Return `Result` The `?` operator can only be used in functions that have a return type of diff --git a/2018-edition/src/ch09-03-to-panic-or-not-to-panic.md b/2018-edition/src/ch09-03-to-panic-or-not-to-panic.md index 0563684b5..0d4cec876 100644 --- a/2018-edition/src/ch09-03-to-panic-or-not-to-panic.md +++ b/2018-edition/src/ch09-03-to-panic-or-not-to-panic.md @@ -192,7 +192,7 @@ impl Guess { } ``` -Listing 9-9: A `Guess` type that will only continue with +Listing 9-10: A `Guess` type that will only continue with values between 1 and 100 First, we define a struct named `Guess` that has a field named `value` that diff --git a/2018-edition/src/ch12-02-reading-a-file.md b/2018-edition/src/ch12-02-reading-a-file.md index 9e70465cb..76e95a8b9 100644 --- a/2018-edition/src/ch12-02-reading-a-file.md +++ b/2018-edition/src/ch12-02-reading-a-file.md @@ -32,7 +32,7 @@ shown in Listing 12-4: ```rust,should_panic use std::env; -use std::fs::File; +use std::fs; use std::io::prelude::*; fn main() { @@ -45,11 +45,8 @@ fn main() { // --snip-- println!("In file {}", filename); - let mut f = File::open(filename).expect("file not found"); - - let mut contents = String::new(); - f.read_to_string(&mut contents) - .expect("something went wrong reading the file"); + let contents = fs::read_to_string(filename) + .expect("Something went wrong reading the file"); println!("With text:\n{}", contents); } @@ -59,22 +56,18 @@ fn main() { by the second argument First, we add some more `use` statements to bring in relevant parts of the -standard library: we need `std::fs::File` to handle files, and +standard library: we need `std::fs` to handle files, and `std::io::prelude::*` contains various useful traits for doing I/O, including file I/O. In the same way that Rust has a general prelude that brings certain -types and functions into scope automatically, the `std::io` module has its own -prelude of common types and functions you’ll need when working with I/O. Unlike -with the default prelude, we must explicitly add a `use` statement for the -prelude from `std::io`. +types and functions into scope automatically, the `std::io` module has its +own prelude of common types and functions you’ll need when working with I/O. +Unlike with the default prelude, we must explicitly add a `use` statement for +the prelude from `std::io`. -In `main`, we’ve added three statements: first, we get a mutable handle to the -file by calling the `File::open` function and passing it the value of the -`filename` variable. Second, we create a variable called `contents` and set it -to a mutable, empty `String`. This will hold the content of the file after we -read it in. Third, we call `read_to_string` on our file handle and pass a -mutable reference to `contents` as an argument. +In `main`, we’ve added a new statement: `fs::read_to_string` will take the +`filename`, open that file, and then produce a new `String` with its contents. -After those lines, we’ve again added a temporary `println!` statement that +After that lines, we’ve again added a temporary `println!` statement that prints the value of `contents` after the file is read, so we can check that the program is working so far. diff --git a/2018-edition/src/ch12-03-improving-error-handling-and-modularity.md b/2018-edition/src/ch12-03-improving-error-handling-and-modularity.md index 072400699..0c4a3c708 100644 --- a/2018-edition/src/ch12-03-improving-error-handling-and-modularity.md +++ b/2018-edition/src/ch12-03-improving-error-handling-and-modularity.md @@ -146,7 +146,8 @@ fn main() { println!("Searching for {}", config.query); println!("In file {}", config.filename); - let mut f = File::open(config.filename).expect("file not found"); + let contents = fs::read_to_string(config.filename) + .expect("Something went wrong reading the file"); // --snip-- } @@ -466,10 +467,7 @@ fn main() { } fn run(config: Config) { - let mut f = File::open(config.filename).expect("file not found"); - - let mut contents = String::new(); - f.read_to_string(&mut contents) + let contents = fs::read_to_string(config.filename) .expect("something went wrong reading the file"); println!("With text:\n{}", contents); @@ -503,10 +501,7 @@ use std::error::Error; // --snip-- fn run(config: Config) -> Result<(), Box> { - let mut f = File::open(config.filename)?; - - let mut contents = String::new(); - f.read_to_string(&mut contents)?; + let contents = fs::read_to_string(config.filename)?; println!("With text:\n{}", contents); @@ -530,7 +525,7 @@ have to specify what particular type the return value will be. This gives us flexibility to return error values that may be of different types in different error cases. -Second, we’ve removed the calls to `expect` in favor of `?`, as we talked about +Second, we’ve removed the call to `expect` in favor of `?`, as we talked about in Chapter 9. Rather than `panic!` on an error, `?` will return the error value from the current function for the caller to handle. diff --git a/2018-edition/src/ch12-04-testing-the-librarys-functionality.md b/2018-edition/src/ch12-04-testing-the-librarys-functionality.md index 7bd761bc5..6a836c0f0 100644 --- a/2018-edition/src/ch12-04-testing-the-librarys-functionality.md +++ b/2018-edition/src/ch12-04-testing-the-librarys-functionality.md @@ -279,8 +279,7 @@ will print each line returned from `search`: pub fn run(config: Config) -> Result<(), Box> { let mut f = File::open(config.filename)?; - let mut contents = String::new(); - f.read_to_string(&mut contents)?; + let contents = fs::read_to_string(config.filename)?; for line in search(&config.query, &contents) { println!("{}", line); diff --git a/2018-edition/src/ch20-01-single-threaded.md b/2018-edition/src/ch20-01-single-threaded.md index 2fb40efbe..5867b47f4 100644 --- a/2018-edition/src/ch20-01-single-threaded.md +++ b/2018-edition/src/ch20-01-single-threaded.md @@ -366,17 +366,14 @@ and send it. ```rust # use std::io::prelude::*; # use std::net::TcpStream; -use std::fs::File; +use std::fs; // --snip-- fn handle_connection(mut stream: TcpStream) { let mut buffer = [0; 512]; stream.read(&mut buffer).unwrap(); - let mut file = File::open("hello.html").unwrap(); - - let mut contents = String::new(); - file.read_to_string(&mut contents).unwrap(); + let contents = fs::read_to_string("hello.html").unwrap(); let response = format!("HTTP/1.1 200 OK\r\n\r\n{}", contents); @@ -421,7 +418,7 @@ received against what we know a request for */* looks like and adds `if` and ```rust # use std::io::prelude::*; # use std::net::TcpStream; -# use std::fs::File; +# use std::fs; // --snip-- fn handle_connection(mut stream: TcpStream) { @@ -431,10 +428,7 @@ fn handle_connection(mut stream: TcpStream) { let get = b"GET / HTTP/1.1\r\n"; if buffer.starts_with(get) { - let mut file = File::open("hello.html").unwrap(); - - let mut contents = String::new(); - file.read_to_string(&mut contents).unwrap(); + let contents = fs::read_to_string("hello.html").unwrap(); let response = format!("HTTP/1.1 200 OK\r\n\r\n{}", contents); @@ -476,17 +470,14 @@ indicating the response to the end user. ```rust # use std::io::prelude::*; # use std::net::TcpStream; -# use std::fs::File; +# use std::fs; # fn handle_connection(mut stream: TcpStream) { # if true { // --snip-- } else { let status_line = "HTTP/1.1 404 NOT FOUND\r\n\r\n"; - let mut file = File::open("404.html").unwrap(); - let mut contents = String::new(); - - file.read_to_string(&mut contents).unwrap(); + let contents = fs::read_to_string("404.html").unwrap(); let response = format!("{}{}", status_line, contents); @@ -544,7 +535,7 @@ the large `if` and `else` blocks. ```rust # use std::io::prelude::*; # use std::net::TcpStream; -# use std::fs::File; +# use std::fs; // --snip-- fn handle_connection(mut stream: TcpStream) { @@ -560,10 +551,7 @@ fn handle_connection(mut stream: TcpStream) { ("HTTP/1.1 404 NOT FOUND\r\n\r\n", "404.html") }; - let mut file = File::open(filename).unwrap(); - let mut contents = String::new(); - - file.read_to_string(&mut contents).unwrap(); + let contents = fs::read_to_string(filename).unwrap(); let response = format!("{}{}", status_line, contents); diff --git a/2018-edition/src/ch20-03-graceful-shutdown-and-cleanup.md b/2018-edition/src/ch20-03-graceful-shutdown-and-cleanup.md index 23904e7bc..793901fe4 100644 --- a/2018-edition/src/ch20-03-graceful-shutdown-and-cleanup.md +++ b/2018-edition/src/ch20-03-graceful-shutdown-and-cleanup.md @@ -389,7 +389,7 @@ use hello::ThreadPool; use std::io::prelude::*; use std::net::TcpListener; use std::net::TcpStream; -use std::fs::File; +use std::fs; use std::thread; use std::time::Duration; @@ -424,10 +424,7 @@ fn handle_connection(mut stream: TcpStream) { ("HTTP/1.1 404 NOT FOUND\r\n\r\n", "404.html") }; - let mut file = File::open(filename).unwrap(); - let mut contents = String::new(); - - file.read_to_string(&mut contents).unwrap(); + let contents = fs::read_to_string(filename).unwrap(); let response = format!("{}{}", status_line, contents);