46
fn main() {
    let _one = None.unwrap_or("one".to_string());
    let _two = None.unwrap_or_else(|| "two".to_string());
}

Any particular reason why people should prefer unwrap_or_else over unwrap_or?

I have seen comments that unwrap_or is eager (this as an example). Does that mean the values in unwrap_or are always evaluated before program execution? And the FnOnce values in unwrap_or_else is called only when the program execute up to that line?

0x00A5
  • 1,462
  • 1
  • 16
  • 20
  • It’s a call, so the arguments are always evaluated. The documentation for `unwrap_or_else` also says as much. – Ry- Jun 23 '19 at 18:09
  • Why do you use `||` instead of `|` for Boolean conditionals? They would both work, but `||` has a distinct advantage. – Silvio Mayolo Jun 23 '19 at 18:14
  • @SilvioMayolo that's the closure referred to as `FnOnce`, not a boolean? https://doc.rust-lang.org/std/option/enum.Option.html#method.unwrap_or_else – Jason Jan 25 '20 at 01:14
  • 1
    @Jason Sorry if my comment's not clear. I wasn't implying that the `||` in the code above is a Boolean or. I was meaning to draw analogy between `|, ||` and the relationship between `unwrap_or` and `unwrap_or_else`. i.e. the latter of both pairs short-circuits. – Silvio Mayolo Jan 25 '20 at 16:59
  • 2
    @SilvioMayolo thank you! That's very kind of you to explain. I am trying to grok the language as a beginner and your comment left me confused at first, not knowing you referred to bitwise `|` and logical `||`. If I understood you correctly, it's the same as short-circuiting with `&&` and `&`. I feel a bit silly now :-) – Jason Jan 25 '20 at 17:26
  • 1
    @Jason Exactly! Sounds like you've got it right. – Silvio Mayolo Jan 25 '20 at 19:33

1 Answers1

75

Both are evaluated during the program's execution and can be arbitrary values. The difference is that:

  • With unwrap_or the fallback value is evaluated just before unwrap_or is called, and therefore is evaluated whether it's needed or not (because Rust is an eager language).
  • With unwrap_or_else the fallback value is evaluated only when unwrap_or_else triggers it (by invoking the function you pass), and therefore is evaluated only if it's needed.
Theodoros Chatzigiannakis
  • 28,773
  • 8
  • 68
  • 104
  • 1
    let _two = None.unwrap_or_else(|| "two".to_string()); doesn't worked for me but let _two = None.unwrap_or_else(| _ | "two".to_string()); does any idea why? – Haseeb Saeed Mar 16 '22 at 00:26