if let Some(x) = some_option.replace(X::new()) {
// do some stuff
}
some_option
.as_mut()
.map(|new_x| new_x.something())
.expect("won't fail because of the replace call above")
I'm trying to avoid the expect, which seems like it should be doable. But I can't figure out how.
I can replace the .replace() call with .take(), and then set the option later, but that still leaves me with lifetime issues since setting some_option = Some(new_x) requires moving new_x, so I can't then return new_x.something() which requires a mutable borrow of new_x.
Is there some way to chain the setting of an option that returns a reference to the new value?
This is by no means a perfect solution, but: Option::get_or_insert_with is really useful in situations like this.
The problem with get_or_insert_with in your situation is: you can't easily tell, from the outside, whether it is get-ing or insert-ing. Here's a version that uses a mutable local variable to track that; I consider it somewhat ugly because it mentions the new value twice.
let mut inserted = false;
let option_ref = some_option.get_or_insert_with(|| {
inserted = true;
X::new()
});
if !inserted { *option_ref = X::new() }
option_ref.something()
While I do agree such unwrap/expect is ugly, I'm pretty sure that unwrap-to-panic code will be optimized out in your first example. You've written some_option's enum tag as Some, and compiler can see that nobody changed it since unwrap, so it's trivial for compilers that panic-arm is dead code.