1

I'm creating a macro that matches two expressions and an identifier. I would like to be able to ignore the identifier if it's not needed, but the compiler seems to complain if I use _ there.

My macro:

macro_rules! if_some {
    ($x:expr, $id:ident, $expr:expr) => {
        match $x {
            None => None,
            Some($id) => Some($expr),
        }
    };
}

What I'd like to do:

if_some!(obtain_an_option(), x, do_something_with(x))

and

if_some!(obtain_an_option(), _, do_something())

The second call fails.

I worked around it by defining a second macro if_some_! that doesn't receive an identifier (I could not use a second pattern either). I'm sure there's a way to say "here accept an identifier or just _.

Maybe there's already a macro/function for this (like Option::map now I think about it)... nevertheless it'd be nice to now.

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
helios
  • 13,574
  • 2
  • 45
  • 55

2 Answers2

5

The simplest way is to add a second arm that matches an underscore:

macro_rules! if_some {
    ($x:expr, _, $expr:expr) => {
        match $x {
            None => None,
            Some(_) => Some($expr),
        }
    };

    ($x:expr, $id:ident, $expr:expr) => {
        match $x {
            None => None,
            Some($id) => Some($expr),
        }
    };
}

And, yes, this sounds like you just want Option::map.

helios
  • 13,574
  • 2
  • 45
  • 55
DK.
  • 55,277
  • 5
  • 189
  • 162
4

Option::map seems to be the best solution for this particular problem, but when you really need a macro which expect both idents and _ as a pattern, you can also use the $p:pat fragment. The fragment of course accepts a broader range of patterns like (ref x, y), but typically this will be acceptable.

macro_rules! if_some {
    ($x:expr, $p:pat, $expr:expr) => {
        match $x {
            None => None,
            Some($p) => Some($expr),
        }
    };
}

fn main() {
    println!("{:?}", if_some!(Some(12), x, x + 1)); // Some(13)
    println!("{:?}", if_some!(Some(12), _, 1)); // Some(1)
}
Masaki Hara
  • 3,295
  • 21
  • 21