Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
570 views
in Technique[技术] by (71.8m points)

error handling - Should I avoid unwrap in production application?

It's easy to crash at runtime with unwrap:

fn main() {
    c().unwrap();
}

fn c() -> Option<i64> {
    None
}

Result:

   Compiling playground v0.0.1 (file:///playground)
 Running `target/debug/playground`
thread 'main' panicked at 'called `Option::unwrap()` on a `None` value', ../src/libcore/option.rs:325
note: Run with `RUST_BACKTRACE=1` for a backtrace.
error: Process didn't exit successfully: `target/debug/playground` (exit code: 101)

Is unwrap only designed for quick tests and proofs-of-concept?

I can not affirm "My program will not crash here, so I can use unwrap" if I really want to avoid panic! at runtime, and I think avoiding panic! is what we want in a production application.

In other words, can I say my program is reliable if I use unwrap? Or must I avoid unwrap even if the case seems simple?

I read this answer:

It is best used when you are positively sure that you don't have an error.

But I don't think I can be "positively sure".

I don't think this is an opinion question, but a question about Rust core and programming.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

While the whole “error handling”-topic is very complicated and often opinion based, this question can actually be answered here, because Rust has rather narrow philosophy. That is:

  • panic! for programming errors (“bugs”)
  • proper error propagation and handling with Result<T, E> and Option<T> for expected and recoverable errors

One can think of unwrap() as converting between those two kinds of errors (it is converting a recoverable error into a panic!()). When you write unwrap() in your program, you are saying:

At this point, a None/Err(_) value is a programming error and the program is unable to recover from it.


For example, say you are working with a HashMap and want to insert a value which you may want to mutate later:

age_map.insert("peter", 21);
// ...

if /* some condition */ {
    *age_map.get_mut("peter").unwrap() += 1;
}

Here we use the unwrap(), because we can be sure that the key holds a value. It would be a programming error if it didn't and even more important: it's not really recoverable. What would you do when at that point there is no value with the key "peter"? Try inserting it again ... ?

But as you may know, there is a beautiful entry API for the maps in Rust's standard library. With that API you can avoid all those unwrap()s. And this applies to pretty much all situations: you can very often restructure your code to avoid the unwrap()! Only in a very few situation there is no way around it. But then it's OK to use it, if you want to signal: at this point, it would be a programming bug.


There has been a recent, fairly popular blog post on the topic of “error handling” whose conclusion is similar to Rust's philosophy. It's rather long but worth reading: “The Error Model”. Here is my try on summarizing the article in relation to this question:

  • deliberately distinguish between programming bugs and recoverable errors
  • use a “fail fast” approach for programming bugs

In summary: use unwrap() when you are sure that the recoverable error that you get is in fact unrecoverable at that point. Bonus points for explaining “why?” in a comment above the affected line ;-)


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...