Подберите подчеркивание вместо идент в макросе

Я создаю макрос, который соответствует двум выражениям и идентификатору. Я хотел бы иметь возможность игнорировать идентификатор, если он не нужен, но компилятор, кажется, жалуется, если я использую _ там.

Мой макрос:

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

Что я хотел бы сделать:

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

а также

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

Второй вызов не проходит.

Я обошел это, определив второй макрос if_some_! это не получает идентификатор (я не мог использовать второй образец также). Я уверен, что есть способ сказать "здесь принять идентификатор или просто _,

Может быть, уже есть макрос / функция для этого (например, Option::map сейчас думаю об этом)... тем не менее было бы неплохо сейчас.

2 ответа

Решение

Option::map кажется, лучшее решение для этой конкретной проблемы, но когда вам действительно нужен макрос, который ожидает и ident, и _ в качестве шаблона, вы также можете использовать $p:pat фрагмент. Фрагмент, конечно, принимает более широкий спектр шаблонов, таких как (ref x, y), но обычно это будет приемлемо.

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)
}

Самый простой способ - добавить вторую руку, которая соответствует подчеркиванию:

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),
        }
    };
}

И да, это звучит так, как будто вы просто хотите Option::map,

Другие вопросы по тегам