Result

  • Result<T, E>  is the type used for returning and propagating errors.

  • It is an enum with the variants, Ok(T) , representing success and containing a value, and Err(E) , representing error and containing an error value.

enum Result<T, E> {
   Ok(T),
   Err(E),
}
#[derive(Debug)]
enum Version { Version1, Version2 }

fn parse_version(header: &[u8]) -> Result<Version, &'static str> {
    match header.get(0) {
        None => Err("invalid header length"),
        Some(&1) => Ok(Version::Version1),
        Some(&2) => Ok(Version::Version2),
        Some(_) => Err("invalid version"),
    }
}

let version = parse_version(&[1, 2, 3, 4]);
match version {
    Ok(v) => println!("working with version: {v:?}"),
    Err(e) => println!("error parsing header: {e:?}"),
}

The ?  operator

  • The operator is defined to perform an early return of a value out of the function

  • The ?  operator can only be used in functions whose return type is compatible with the value the ?  is used on.

    • We’re only allowed to use the ?  operator in a function that returns Result , Option , or another type that implements FromResidual .

    • By default, use Result .

  • Usage :

    use std::fs::File;
    use std::io::{self, Read};
    
    fn read_username_from_file() -> Result<String, io::Error> {
        let mut username_file = File::open("hello.txt")?;
        let mut username = String::new();
        username_file.read_to_string(&mut username)?;
        Ok(username)
    }
    
    use std::fs::File;
    use std::io::{self, Read};
    
    fn read_username_from_file() -> Result<String, io::Error> {
        let mut username = String::new();
    
        File::open("hello.txt")?.read_to_string(&mut username)?;
    
        Ok(username)
    }
    
  • Ex1 :

    • Without ? :

      use std::fs::File;
      use std::io::prelude::*;
      use std::io;
      
      struct Info {
          name: String,
          age: i32,
          rating: i32,
      }
      
      fn write_info(info: &Info) -> io::Result<()> {
          // Early return on error
          let mut file = match File::create("my_best_friends.txt") {
                 Err(e) => return Err(e),
                 Ok(f) => f,
          };
          if let Err(e) = file.write_all(format!("name: {}\n", info.name).as_bytes()) {
              return Err(e)
          }
          if let Err(e) = file.write_all(format!("age: {}\n", info.age).as_bytes()) {
              return Err(e)
          }
          if let Err(e) = file.write_all(format!("rating: {}\n", info.rating).as_bytes()) {
              return Err(e)
          }
          Ok(())
      }
      
    • With ? :

      use std::fs::File;
      use std::io::prelude::*;
      use std::io;
      
      struct Info {
          name: String,
          age: i32,
          rating: i32,
      }
      
      fn write_info(info: &Info) -> io::Result<()> {
          let mut file = File::create("my_best_friends.txt")?;
          // Early return on error
          file.write_all(format!("name: {}\n", info.name).as_bytes())?;
          file.write_all(format!("age: {}\n", info.age).as_bytes())?;
          file.write_all(format!("rating: {}\n", info.rating).as_bytes())?;
          Ok(())
      }
      

Unwrapping