Updating value of reference to Option in function

Hello!

I am attempting to create a function like:

fn increment_value_if_exists(
    value: &mut Option<u8>,
) {
    if let Some(num) = *value {
        value.insert(num + 1);
    }
}

fn main() {
    let mut foo: Option<u8> = Some(1);
    increment_value_if_exists(&mut foo);
    println!("{:?}", foo);

    let mut bar: Option<u8> = None;
    increment_value_if_exists(&mut bar);
    println!("{:?}", bar);
}

Which "works", but gives the warning:

warning: unused return value of `Option::<T>::insert` that must be used
 --> src/main.rs:5:9
  |
5 |         value.insert(num + 1);
  |         ^^^^^^^^^^^^^^^^^^^^^^
  |
  = note: `#[warn(unused_must_use)]` on by default
  = note: if you intended to set a value, consider assignment instead

I know that using .insert is wrong (I'm leveraging a side effect), but I can't seem to get the right incantation of dereferencing or unwrapping to successfully increment the value of the Option reference in the function.

Thanks for any help!

*value = Some(num + 1) would work I believe.

You can also use

if let Some(num) = value {
    *num += 1
}

or equivalently

if let &mut Some(ref mut num) = value {
    *num += 1
}
1 Like

Thanks for the reply, @jhpratt . It indeed works.

Thanks for the reply, @steffahn . Also thank you for the equivalent code. That helps me understand what is actually happening.

By the way: Another equivalent alternative is

if let Some(num) = value.as_mut() {
    *num += 1
}

using Option::as_mut. In this case it's not really necessary to use it, but this function can often be quite useful.

You could then even use

value.as_mut().map(|num| *num += 1);

(although clippy won't like that)

Yet another approach, and one that's using map slightly "more appropriately" (at least as far as the authors of clippy are concerned) would be

*value = value.map(|num| num + 1);

How curious. I was going to suggest that, and indeed this works:

// Non-`Copy` contents
fn f(o: &mut Option<String>) {
    o.as_mut().map(|s| *s += "");
}

As does Clippy's suggestion:

fn g(o: &mut Option<String>) {
    if let Some(s) = o.as_mut() {
        *s += "";
    }
}

But I find both quite clear, so I guess Clippy and I will have to agree to disagree. This however:

// Non-`Copy` contents
fn h(o: &mut Option<String>) {
    *o = o.map(|s| s + "");
}

Does not work, and elicits a nonsense suggestion from rustc (#90286 probably):

help: consider borrowing the `Option`'s content
   |
12 |     *o = o.map(|s| s + "").as_ref();
   |                           +++++++++

Playground.

I don't consider the version with map as clear as the if let. The map method is lazy in most contexts, and it's purpose is to create a new Option rather than to have a side-effect.

1 Like

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.