A Rust function returns a Result when it may succeed or fail. Result has two states: Ok holds a successful value, and Err holds an error value. This lets a function report more than a simple true-or-false outcome, such as an operating system error when a file operation fails. section 3.4.2 section 3.4
Returning a file or an explanation
A file-opening method can return Result<File, String>: Ok(File) on success or Err(String) with an error message. A read method can similarly return Result<usize, String>, using Ok to hold the number of bytes read. The return type makes the possibility of failure visible to the caller. section 3.4.2
Listing 3.8 Using Result to mark functions liable to filesystem errors
use rand::prelude::*; #1
fn one_in(denominator: u32) -> bool { #2
thread_rng().gen_ratio(1, denominator) #3
}
#[derive(Debug)]
struct File {
name: String,
data: Vec<u8>,
}
impl File {
fn new(name: &str) -> File {
File {
name: String::from(name),
data: Vec::new()
} #4
}
fn new_with_data(name: &str, data: &Vec<u8>) -> File {
let mut f = File::new(name);
f.data = data.clone();
f
}
fn read(
self: &File,
save_to: &mut Vec<u8>,
) -> Result<usize, String> { #5
let mut tmp = self.data.clone();
let read_length = tmp.len();
save_to.reserve(read_length);
save_to.append(&mut tmp);
Ok(read_length) #6
}
}
fn open(f: File) -> Result<File, String> {
if one_in(10_000) { #7
let err_msg = String::from("Permission denied");
return Err(err_msg);
}
Ok(f)
}
fn close(f: File) -> Result<File, String> {
if one_in(100_000) { #8
let err_msg = String::from("Interrupted by signal!");
return Err(err_msg);
}
Ok(f)
}
fn main() {
let f4_data: Vec<u8> = vec![114, 117, 115, 116, 33];
let mut f4 = File::new_with_data("4.txt", &f4_data);
let mut buffer: Vec<u8> = vec![];
f4 = open(f4).unwrap(); #9
let f4_length = f4.read(&mut buffer).unwrap(); #9
f4 = close(f4).unwrap(); #9
let text = String::from_utf8_lossy(&buffer);
println!("{:?}", f4);
println!("{} is {} bytes long", &f4.name, f4_length);
println!("{}", text);
}
The file example shows Result in a method signature and Ok around a successful read length. section 3.4.2
To get a successful value out, unwrap() removes its Ok wrapper. It also crashes the program if the Result is Err, so it is a convenient first demonstration rather than a robust way to handle errors. The same pattern appears when try_into() converts a u16 to an i32: the conversion returns a Result before its value is used in a comparison. section 3.4.2 section 2.3.3
Result remains useful beyond the file example. A time-setting operation should return Result because the operating system may reject it, perhaps for lack of permission. When library code combines Results from different upstream crates, their error types also become a practical concern for use of the ? operator. section 9.8 section 8.5







