One-liner to convert `()` to `None`

Hi, I often have code like this

let foo: Option<T> = match bar {
    A => Some(baz()),
    B => {
        qux();
        None
    }
};

Is there some nicer way to do it? The best I've come to is to define none = |()| None and have none(qux()), but it still requires one additional line and generally having (...) around the function call is not nice.

Presumably qux is used elsewhere in a way that you want to retain its () return type; but if not, you can make it polymorphic and return None instead.

You can also define a trait that unconditionally returns None and implement it for ():

trait IntoNone: Sized {
    fn into_none<T>(self) -> Option<T> {
        None
    }
}
impl IntoNone for () {}

Then simply call qux().into_none().

Frame challenge: This situation only comes up in the first place because qux() has side effects. So, IMHO,

  • if baz() doesn't have any side effects, what you wrote is exactly what I would personally like to see, and
  • if baz() does have side effects, I think I'd actually prefer
    let foo: Option<T> = match bar {
        A => {
            let t = baz();
            Some(t)
        }
        B => {
            qux();
            None
        }
    };
    
    and maybe the entire match expression should really be a method do_baz_or_qux on bar then, which in some cases I might write like
    fn do_baz_or_qux(self) -> Option<T> {
        match self {
            A => {
                let t = baz();
                return Some(t);
            }
            B => {
                qux();
            }
        };
        None
    }
    
    to emphasize the side effects.

(Of course, I may just be reading too much into this specific example.)

4 Likes

I thought of this but don't actually like them; they're worse than your none.

    let foo = match bar {
        A => Ok(baz()),
        B => Err(quz()),
    }.ok();

    let foo = match bar {
        A => Some(baz()),
        B => Err(quz()).ok(),
    };

If you prefer more functional approach take a look at tap library. You could for example use it like this:

use tap::TapOptional;

let foo = bar
    .into_baz() // returns `Some(baz())` or `None`
    .tap_none(qux); // will only be called if value is None

This will be really nice if qux is for example function that just logs something.

3 Likes

I am unsure whether this might be an x-y problem.
Of what type is bar?
Is it an enum? Are A and B its variants?

What do you dislike about this way?

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.