103

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?

Yilmaz
  • 1
  • 7
  • 79
  • 120
Angel Angel
  • 16,564
  • 27
  • 71
  • 101
  • 2
    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 thanks for the very useful link and sorry for my English – Angel Angel Apr 01 '16 at 17:33
  • 3
    There's no need to apologize for poor English; so long as someone is able to understand the question, we can clean it up. Just be sure to search for previous questions and explain why your question isn't a duplicate of them. – Shepmaster Apr 01 '16 at 17:36
  • @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

2 Answers2

132

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
  • 86,825
  • 11
  • 134
  • 175
  • 1
    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
  • 19
    @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
  • 5
    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
  • 7
    @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
  • 4
    @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
  • @rodrigo ok thx that's what i needed to make sure of – Ben Apr 23 '21 at 17:49
1

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
  • 1
  • 7
  • 79
  • 120