Understanding Result , unwrap

Can someone explain me Result , unwrap, etc. in simple understandable words?

I studied this and seems all points are clear. But if something is a bit different clarity evaporates, disappears

https://www.tutorialspoint.com/rust/rust_error_handling.htm

use std::fs::File;
   let f = File::open("main.jpg");   // main.jpg doesn't exist
   match f {
      Ok(f)=> {
         println!("file found {:?}",f);
      },
      Err(e)=> {
         println!("file not found \n{:?}",e);   //handled error
      }
   }

I try this, and it works fine

 use std ::  fs  ;
 fs  ::  remove_file (   "data.txt"  )   .   expect  (   "could not remove file" )   ;
println !   (   "file is removed"   )   ;

But it stops execution (panic). I want delete file only if it exists, if not, ok, go forward.. do not stop...

let del = fs  ::  remove_file (   "data.txt"  )   .Result<bool,String>  ;
    match del {
        Ok ( del )   => {
           println  !   (   "file foundfile is removed{:?}"   ,   del   )   ;
        } ,
        Err ( e ) => {
           println  !   (   "file not foundcould not remove file \n{:?   }   "   ,   e   )   ;   //handled error
        }
     }

I could find similar code, but now I want to understand the situation deeply.

Excuse, me, if my question is annoying, distracting...

The unwrap or expect functions will crash the program if the operation failed.

If you want to ignore an error, you can instead do this:

let _ = fs::remove_file("data.txt");
2 Likes

The return value of std::fs::remove_file is an std::io::Result<()>, which is is a std::result::Result<(), std::io::Error>.

This is a bit confusing. Basically this means, the result of remove_file can be one of the following:

  • Ok(())
  • Err(some_io_error)

When you call .unwrap(), then any value other than Ok(some_value) will cause a panic and abort normal program flow.


Generally, if a method returns a result, the compiler will warn you if you do not check for the error:

fn foo() -> Result<(), ()> {
    Ok(())
}

fn main() {
    foo();
}

(Playground)


As @alice showed, you can ignore the error with the let _ = syntax:

fn foo() -> Result<(), ()> {
    Ok(())
}

fn main() {
    let _ = foo();
}

(Playground)


Another possiblity is to use the match construct to check whether the result is Ok or Err:

fn foo() -> Result<(), ()> {
    Ok(())
}

fn main() {
    let res = foo();
    match res {
        Ok(_) => println!("That went okay!"),
        Err(_) => println!("Urgh... Didn't work!")
    }
}

(Playground)

Output:

That went okay!

Note that instead of discarding the result with let _ =, we store the result in a variable res, which also keeps the compiler from complaining (as long as we use that res value afterwards). Then the match construct distinguishes between the Ok and Err cases.

It's also possible to write it more concise, like this:

fn foo() -> Result<(), ()> {
    Ok(())
}

fn main() {
    match foo() {
        Ok(_) => println!("That went okay!"),
        Err(_) => println!("Urgh... Didn't work!")
    }
}

(Playground)

Output:

That went okay!


Finally, if the Result carries a value other than (), you can use pattern matching to extract the value:

fn foo() -> Result<(), &'static str> {
    Err("I couldn't do my work.")
}

fn main() {
    match foo() {
        Ok(_) => println!("That went okay!"),
        Err(err) => println!("We encountered an error: {err}")
    }
}

(Playground)

Output:

We encountered an error: I couldn't do my work.

7 Likes