157

I have this code that uses .unwrap():

fn main() {
    let paths = std::fs::read_dir("/home/user").unwrap();

    for path in paths {
        println!("Name: {}", path.unwrap().path().display());

    }
}

After looking at the definition of unwrap,

pub fn unwrap(self) -> T {
  match self {
        Ok(t) => t,
        Err(e) => unwrap_failed("called `Result::unwrap()` on an `Err` value", e),
    }
}

And the signature of read_dir

pub fn read_dir<P: AsRef<Path>>(path: P) -> io::Result<ReadDir>

Am I correct in understanding that unwrap returns the T type that is passed in Result?

Aryan Beezadhur
  • 4,503
  • 4
  • 21
  • 42
Angel Angel
  • 19,670
  • 29
  • 79
  • 105
  • 3
    See also [What is this unwrap thing](http://stackoverflow.com/q/21257686/155423) and maybe [What's the benefit of using a Result?](http://stackoverflow.com/q/22187926/155423). – Shepmaster Apr 01 '16 at 17:24
  • @Shepmaster the first link if I had seen him, but I found it rather the difference between one thing and another, and there was talk of "Option", I was not sure if we talk about the same "Result" now I understand better, thanks to the response, now could be understood in any way as a duplicate, on the second link I had not seen before, thanks for everything – Angel Angel Apr 01 '16 at 18:01

3 Answers3

190

In Rust, when you have an operation that may either return a T or fail, you will have a value of type Result<T,E> or Option<T> (E will be the error condition in case of an interesting error).

The function unwrap(self) -> T will give you the embedded T if there is one. If instead there is not a T but an E or None then it will panic.

It is best used when you are positively sure that you don't have an error. If that is not the case usually it is better either pattern-match the error or use the try! macro ? operator to forward the error.

In your example, the call to read_dir() returns a io::Result<ReadDir> because opening the directory might fail. And iterating the opened directory returns multiple values of type io::Result<DirEntry> because reading the directory might also fail.

With try! ? it would be something like this:

fn try_main() -> std::io::Result<()> {
    let entries = std::fs::read_dir("/home/user")?;

    for entry in entries {
        println!("Name: {}", entry?.path().display());

    }
    Ok(())
}

fn main() {
    let res = try_main();

    if let Err(e) = res {
        println!("Error: {}", e);
    }
}

Look how every error case is checked.

(Updated to use ? instead of try!(). The macro still works, but the ? is preferred for new code).

rodrigo
  • 94,151
  • 12
  • 143
  • 190
  • 2
    Thanks for the greaty explanation @rodrigo. What excatly do you mean by `interesting error` - one that is known or catchable(as in other languages)? – Rajeev Ranjan May 24 '18 at 03:53
  • 27
    @RajeevRanjan: Think for example of opening a file: it can fail because you lack permissions, or because the file does not exist, or because you requested write permission and it is read-only, or because the filesystem is corrupted, or it is a remote filesystem and the network is down... that's interesting! and you may want to know why it is failing. OTOH, looking up a value in a hash table or a dictionary, if it is not there, that's it, it is not an interesting error and there is no extra error code or data to get. The first case will be a `Result`, the second one a `Option`. – rodrigo May 24 '18 at 14:06
  • 6
    Rust should look for an alternative to this junk.. somethimes i see some code like a.unwrap().b.unwrap().c its a mess. – Serak Shiferaw Sep 23 '19 at 11:43
  • 9
    @SerakShiferaw: Well, the alternative to `unwrap()` is to use the `?` operator. Errors and failures are just a fact of the programming life. Other languages either use exceptions, error codes, or directly dismiss any errors... they all have pros and cons. – rodrigo Sep 23 '19 at 17:27
  • @rodrigo "?" is awesome, but it does not work everywhere and failure create is also a good option but there are some places where you cant avoid unwrap() i am not sure if they are still migration to the question mark or this is how its doing to be in the future – Serak Shiferaw Sep 24 '19 at 08:15
  • @SerakShiferaw: There is the [try_trait](https://doc.rust-lang.org/unstable-book/library-features/try-trait.html) and the [try_blocks](https://doc.rust-lang.org/unstable-book/language-features/try-blocks.html) unstable features that will make this somewhat easier. – rodrigo Sep 24 '19 at 10:01
  • @rodrigo chain function is ergonomic a.foo().baz().bar()? without the unwrap look how success a.onsuccess(){//do this}.onerror(e){console.log(e)} – Serak Shiferaw Oct 04 '19 at 10:19
  • not an very experienced rust user, but so far it looks like unwrap() is the poor guy' solution; more of a workaround when you're not skilled enough to write necessaries (time consuming) verifications.. am i right to think that ? Rust is super strict, then you get unwrap which make it completely unstrict; so then am wondering why it's there as it would just lead to poor patterns – Ben Apr 23 '21 at 10:17
  • 7
    @Ben: Too many `unwrap()` are a sign of sloppy programming, which is ok if it is a prototype or a run-and-throw-away program. Some `unwrap()` that cannot (or should not) fail are ok, such as `NonZeroU32::new(1).unwrap()`: if your assumption is wrong and it fails, the program panics, a kind of bug-check abort, that is the correct result. – rodrigo Apr 23 '21 at 17:45
  • Not being a Rust programmer, using `unwrap()` seems like bad practice, like you're ignoring the possibility of errors and/or ignoring the problem. It seems similar to always using the `!` operator in Typescript rather than explicitly checking for undefined values and handling that case properly. `unwrap_or()`, on the other hand, seems to appropriately and sensibly handle the error cases by explicitly providing an alternative. – Clonkex Jul 21 '22 at 01:59
  • 1
    @Clonkex: `unwrap()` does not actually ignore the error, but it `panics!` instead. It is still useful if you are positive that you have a `Some/Ok` or if you want to abort on error, such as with a simple command-line tool, or if you have a `catch_unwind` somewhere and you treat `panic!` a bit like an unexpected exception... But in general `unwrap_or()` or bubble up the error with `?` should be preferred, of course. – rodrigo Jul 28 '22 at 07:05
  • @rodrigo I know, I just mean that by using `unwrap()`, the developer is ignoring the potential for an error and thus allowing a crash if an error occurs. Better to specifically account for the possibility. I can see how it's reasonable to use if you never expect an error and have no way to properly handle it if it does occur, but my philosophy is that it's better to avoid having to reason about all possible paths the program could take at runtime and simply account for the possibility of errors (which is why I'm a big fan of nullable reference type annotations in C#). Predictability et cetera. – Clonkex Jul 29 '22 at 01:49
11

The problem is that reading a line from a file produces a potential error type. The type is

       Result<String,std::io::Error>

Result is an enum. There are two potential values in the Result, they are used for error handling and management. The first value is Err. If Err is populated, there was an error in the function that was called. The other potential selection is Ok. Ok contains a value.

enum Result<T, E> {
    Ok(T),
    Err(E),
}

Enum is a complex type, rather than a single value. To get the value we are looking for, we use unwrap() to unwrap the value.

unwrap() is used here to handle the errors quickly. It can be used on any function that returns Result or Option (Option is also enum). If the function returns an Ok(value), you will get the value. If the function returns an Err(error), the program will panic.

Yilmaz
  • 35,338
  • 10
  • 157
  • 202
-3

A replacement for calling unwrap() on a Result or Option.

This macro is intended to be used in all cases where one would unwrap a Result or Option to deliberately panic in case of error, e.g. in test-cases. Such unwraps don't give a precise point of failure in the code and instead indicate some line number in the Rust core library. This macro provides a precise point of failure and decorates the failure for easy viewing.

Abdulrahim Klis
  • 388
  • 3
  • 9