ржавчина-как совместить этот марко с циклом / рекурсивом? - PullRequest
0 голосов
/ 31 мая 2019

У меня есть такой код:

macro_rules! match_token_pattern {
    ($parser:ident, $a:ident) => {{
        let a = $parser.$a();

        if a != None {
            Some(a)
        } else {
            None
        }
    }};

    ($parser:ident, $a:ident, $b:ident) => {{
        let a = $parser.$a();
        let b = $parser.$b();

        if a != None && b != None {
            Some((a, b))
        } else {
            None
        }
    }};

    ($parser:ident, $a:ident, $b:ident, $c:ident) => {{
        let a = $parser.$a();
        let b = $parser.$b();
        let c = $parser.$c();

        if a != None && b != None && c != None {
            Some((a, b, c))
        } else {
            None
        }
    }};
}

Можно ли объединить второе / третье правило с одним? И теперь я пытаюсь использовать переменные параметры marco, но результат marco () похож на Some (a, Some (b, c)) или Some (a, Some (b, Some (c, d))) ...

Спасибо.

1 Ответ

0 голосов
/ 31 мая 2019

Мы можем начать с написания макроса, который принимает любое количество аргументов:

macro_rules! match_token_patten {
    ($parser:ident, $($arg:ident),*)) => {{
        /* macro body */
    }};
}

$($arg:ident),* будет захватывать любые числовые идентификаторы, разделенные запятыми.

Далее нам нужно вычислить результаты для каждого метода. Простой способ сделать это - просто сохранить их в кортеже, например, (parser.a(), parser.b(), parser.c()). Мы будем использовать синтаксис $( ... ),* снова, чтобы расширить захваченные переменные аргументы:

macro_rules! match_token_patten {
    ($parser:ident, $($arg:ident),*)) => {{
        let results = ( $( $parser.$arg() ),* );
    }};
}

Теперь мы хотим превратить (Some(x), Some(y), ...) в Some((x, y, ...)). Мы можем использовать сопоставление с образцом для этого! Мы можем написать это как:

if let (Some(a), Some(b), Some(c)) = results {
    // only if results is a tuple of three Some values
    Some((a, b, c)
} else {
    // at least one of the results is None
    None
}

Наконец, записав это в форме макроса variadic, мы получим:

macro_rules! match_token_pattern {
    ($parser:ident, $($a:ident),*) => {{
        let results = ( $($parser.$a()),* );
        if let ( $(Some($a)),* ) = results {
            Some( ( $($a),* ) )
        } else {
            None
        }
    }};
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...