liveBook · Manning

Result type

As explained in Rust in Action: Systems programming concepts and techniques

Result is Rust's standard result type that contains either a successful value or an error value.

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

How Rust in Action: Systems programming concepts and techniques covers it

How deep it goes
Defines Ok and Err and demonstrates return signatures and unwrap(), while deferring more sophisticated error handling.
Examples
Uses file-opening and reading methods, a u16-to-i32 conversion, and a time-setting operation.
What it assumes
Builds on typed values, functions, and methods; introduces Result’s two states before explaining fuller error handling.
What you can do after
Build it from scratch: give potentially failing file methods Result return types and recognize why unwrap() is risky.
How it connects
Connects Result to fallible type conversion, filesystem errors, the ? operator, and operating-system error reporting.

Also explained in

Compare how 8 books explain result type →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Rust in Action: Systems programming concepts and techniques. The section links point to the parts of the book it draws on.