ERROR HANDLING

 ERROR HANDLING

  • Rust doesn't have exceptions like other languages.
  • Instead it has type Result<T, E>  for recoverable error and panic macro that stops the execution when the program encounters an unrecoverable error.
  • fn main(){
      let value: Result<&str, Box<dyn std::error::Error>> = Ok("Hello");
    }
  • Box is a reference to a memory in heap, in this case an error.
  • You can access the values ftom result using pattern matching like given below
  • match value {
      Ok(value: &str) => println!("{}", value),
      Err(error: Box<dyn Error>) => println!("Error {}", error)
    }
  • In the below code, the result will either be string or empty error, this is used if the error itself is not important:
  • fn main(){
      let value: Result<&str, ()> = Ok("Hello");
      match value {
         Ok(value: &str) => println!("{}", value),
         Err(_) => println!("Error Occured") 
      }
    } 
  • Or you can use custom error like given below:
  • fn get_username() -> Result<String, ()>{
      Ok("John".to_string())
    }
    
    fn main(){
      let username: String = get_username().expect(msg: "something went wrong");

    } 

  • Can check if the result is an error or an ok using below methods:
  • fn get_username() -> Result<String, ()>{
      Ok("John".to_string())
    }
    
    fn main(){
      let is_okay: bool = get_username().is_ok();
      let is_okay: bool = get_username().is_err();

    } 

  • You can exit early from an error like below
  • fn get_first_name() -> Result<String, ()>{
      Ok("Sanu".to_string())
    }
    
    fn get_last_name() -> Result<String, ()>{
      Ok("Shilshad".to_string())
    }
    
    fn get_full_name() -> Result<String, ()>{
      let first_name: String = get_first_name()?;
      let last_name: String = get_last_name()?;
      Ok(format!("{} {}", first_name, last_name)) 
    }
    
    fn main(){
      let name: Result<&str, ()> = get_full_name();
      match name{
        Ok(value: &str) => println!("{}", value),
        Err(_) => println!("Error occured")  } 

    } 

  • In the above example in case an error occurs in get_last_name function, it propagates into the get_full_name function without breaking anything. The ? unwraps the value, only if the return type of the function is Result.

  • You can perform map on Result like below:

  • 
    fn main(){
      let name: Result<&str, ()> = get_full_name();
      let length: usize = name.map(|x: String| x.len()).unwrap_or_default();

    } 

  • You can map error like below:

  • fn get_first_name() -> Result<String, String>{
      Err("Error".to_string())
    }
    
    fn get_last_name() -> Result<String, String>{
      Ok("Shilshad".to_string())
    }
    
    fn get_full_name() -> Result<String, String>{
      let first_name: String = get_first_name()?;
      let last_name: String = get_last_name()?;
      Ok(format!("{} {}", first_name, last_name)) 
    }
    
    fn main(){
      let name: Result<String, ()> = get_full_name();
      let error_length: Result<String, usize> = name.map_err(op: |e: String| e.len());

    } 

  • You can use ? in main function to unwrap if you add Result as the return type:

  • 
    fn main() -> Result<(), Box<dyn std::error::Error>> {
      let name: String = get_full_name()?;

    } 

Comments