mirror of
https://github.com/rust-lang/book.git
synced 2026-05-18 06:43:34 -04:00
@@ -307,19 +307,22 @@ fn read_username_from_file() -> Result<String, io::Error> {
|
||||
<span class="caption">Listing 9-6: A function that returns errors to the
|
||||
calling code using `match`</span>
|
||||
|
||||
Let’s look at the return type of the function first: `Result<String,
|
||||
io::Error>`. This means the function is returning a value of the type
|
||||
`Result<T, E>` 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<String, io::Error>`. This means the function is returning a value of
|
||||
the type `Result<T, E>` 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:
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
```rust
|
||||
use std::io;
|
||||
use std::io::Read;
|
||||
use std::fs;
|
||||
|
||||
fn read_username_from_file() -> Result<String, io::Error> {
|
||||
fs::read_to_string("hello.txt")
|
||||
}
|
||||
```
|
||||
|
||||
<span class="caption">Listing 9-9: Using `fs::read_to_string`</span>
|
||||
|
||||
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
|
||||
|
||||
@@ -192,7 +192,7 @@ impl Guess {
|
||||
}
|
||||
```
|
||||
|
||||
<span class="caption">Listing 9-9: A `Guess` type that will only continue with
|
||||
<span class="caption">Listing 9-10: A `Guess` type that will only continue with
|
||||
values between 1 and 100</span>
|
||||
|
||||
First, we define a struct named `Guess` that has a field named `value` that
|
||||
|
||||
@@ -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</span>
|
||||
|
||||
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.
|
||||
|
||||
|
||||
@@ -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<Error>> {
|
||||
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.
|
||||
|
||||
|
||||
@@ -279,8 +279,7 @@ will print each line returned from `search`:
|
||||
pub fn run(config: Config) -> Result<(), Box<Error>> {
|
||||
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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user