39

I'm new to rust and trying to understand when should we use unwrap vs expect.

Here's a sample code:

use std::env;

fn main() {
    let args: Vec<String> = env::args().collect();

    let query = args.get(1).unwrap();
    println!("query from unwrawp: {}", query);

    let query = args.get(1).expect("insufficient arguments");
    println!("query from expect: {}", query);

    //$ cargo run hello
    //OUTPUT:
    //query from expect: hello
    //query from unwrawp: hello

}

Only difference I observed is there's a custom panic message in expect.
Are these two interchangeable or are there any special scenarios where we should use one over the other?

manikawnth
  • 2,739
  • 1
  • 25
  • 39
  • 4
    As far as I know they're interchangeable. I generally use `unwrap` in cases where the logic is 100% clear that there won't be a failure and `expect` with a message if there's a possibility of an edge case I haven't considered - or one which may be triggered by incorrect developer-written config files etc. – notquiteamonad Apr 19 '20 at 09:23
  • 1
    This [answer](https://stackoverflow.com/a/39478185/1889329) offers a good overview of the error modes to consider when choosing between one or the other. In a nutshell, `unwrap()` is a way of converting between a recoverable error and an unrecoverable error. On the flip side, when you're calling `expect()`, you assume to be in an unrecoverable error state already. I guess the guiding principle should be: If you cannot recover from a failed `unwrap()` call, choose `expect()` instead and have your diagnostic contain a better error message. – IInspectable Apr 19 '20 at 09:56
  • @IInspectable: I think you misread the answer you are linking to. Both `unwrap` and `expect` convert from recoverable to unrecoverable, the only difference is that one specifies a custom error message and the other doesn't. – Matthieu M. Apr 20 '20 at 17:15
  • 1
    @mat: I guess I mispresented my point. Both `unwrap()` and `expect()` will `panic!()`, when there's nothing to unwrap. In that, they are identical. It's the situation your code is in, that makes the difference. If your code cannot meaningfully continue without the unwrapped value, choose `expect()`. If you can respond to there not being a value, pick `unwrap()` instead, after verifying the value's existence. In that case `unwrap()` will only `panic!()` if there is an issue with your code, which transitions from being in a recoverable state to an unrecoverable state. – IInspectable Apr 21 '20 at 07:11
  • @IInspectable IMO, instead of introducing an `expect` function, it could've simply been named `unwrap_else_panic(&str)` . expect is sounding more like unit test assertion. – manikawnth Apr 21 '20 at 07:33
  • 1
    Both of those options introduce a function. The only difference is in their name. That doesn't change the fact that it was assumed there to be a need for `unwrap()` and something else. That something else was named `expect()`. The particular name isn't as important as the property of being different. That allows you to convey different semantics to a reader of your code. – IInspectable Apr 21 '20 at 07:51
  • @IInspectable Please post your comments as an answer. Use comments to ask for more information or suggest improvements. Avoid answering questions in comments. – John Kugelman May 01 '21 at 11:38

2 Answers2

48

Rust doesn't have function overloading, so there should be a way to declare "unwrap with a message", and that is expect.

  1. expect == unwrap with a message
  2. expect_err == unwrap_err with a message

About usage scenarios of "unwrap vs expect" Rust Book (Ch 9) says:

Using expect instead of unwrap and providing good error messages can convey your intent and make tracking down the source of a panic easier. Because this error message starts with the text we specified... it will be easier to find where in the code this error message is coming from.

Alexander Fadeev
  • 2,110
  • 14
  • 16
  • 5
    FWIW, besides function overloading, the same could be achieved with optional parameters, which Rust also doesn't have. – BlackShift Dec 15 '20 at 21:53
19

Alexander Fadeev's answer is correct, but there's a bit more information from Rust Book (Ch 9):

It would also be appropriate to call unwrap when you have some other logic that ensures the Result will have an Ok value, but the logic isn’t something the compiler understands. You’ll still have a Result value that you need to handle: whatever operation you’re calling still has the possibility of failing in general, even though it’s logically impossible in your particular situation. If you can ensure by manually inspecting the code that you’ll never have an Err variant, it’s perfectly acceptable to call unwrap. Here’s an example:

use std::net::IpAddr;

let home: IpAddr = "127.0.0.1".parse().unwrap();

We’re creating an IpAddr instance by parsing a hardcoded string. We can see that 127.0.0.1 is a valid IP address, so it’s acceptable to use unwrap here. However, having a hardcoded, valid string doesn’t change the return type of the parse method: we still get a Result value, and the compiler will still make us handle the Result as if the Err variant is a possibility because the compiler isn’t smart enough to see that this string is always a valid IP address. If the IP address string came from a user rather than being hardcoded into the program and therefore did have a possibility of failure, we’d definitely want to handle the Result in a more robust way instead.

So if you know that an error is never going to happen, but the compiler wants you to handle errors, unwrap is cleaner and shorter than needing to provide a custom and unnecessary error message if you used expect.

John Kugelman
  • 349,597
  • 67
  • 533
  • 578
Dawngerpony
  • 3,288
  • 2
  • 34
  • 32