Есть ли способ использовать пользовательские шаблоны, такие как регулярное выражение или функции в совпадении?

#rust #macros

#Ржавчина #сопоставление с образцом

Вопрос:

Я пишу игрушечный язык программирования на Rust. Я создал прототип логики синтаксического анализатора на Ruby:

 def rd_tree(chars)
  loop do
    case c = chars.next
    when /s/
      # whitespace stuff
    when "("
      # open paren stuff
    when ")"
      # close paren stuff
    else
      # default stuff
    end
  end
end
  

И теперь я конвертирую его в Rust:

 fn rd_tree(chars: std::str::Chars) {
    while let Some(c) = chars.next() {
        if c.is_whitespace() {
            // whitespace stuff
        } else if c == '(' {
            // open paren stuff
        } else if c == ')' {
            // close paren stuff
        } else {
            // default stuff
        }
    }
}
  

Я прибегнул к использованию цепочки if, else-if, потому что, насколько я могу судить, функция сопоставления Rust ограничена деструктурированием, перечислениями и шаблонами типов. Есть ли способ сопоставления регулярных выражений или логических функций? Если нет, есть ли здесь более идиоматичный шаблон, чем if, else-if? Я ожидаю, что в будущем у логики будет больше ветвей, и я хочу, чтобы она оставалась аккуратной.

Ответ №1:

Пока нет. match Шаблоны должны состоять из элементов, которые могут быть статически проверены компилятором.

Тем не менее, вы можете использовать защиту от совпадений:

 fn rd_tree(chars: std::str::Chars) {
    while let Some(c) = chars.next() {
        match c {
            c if c.is_whitespace() => {}
            '(' => {}
            ')' => {}
            _ => {}
        }
    }
}
  

Защита от совпадения позволяет вам запускать функцию против любого совпадающего шаблона.


В будущем постоянная оценка может быть улучшена, чтобы позволить вызывать функции вместо шаблона:

 #[derive(PartialEq, Eq)]
struct Foo {
    f: usize,
    g: usize,
}

impl Foo {
    const fn repeated(x: usize) -> Self {
        Foo { f: x, g: x }
    }
}

fn main() {
    let f = Foo { f: 0, g: 1 };
    match f {
        const { Foo::repeated(22) } => println!("hi"),
        _ => println!("1"),
    }
}
  

Эта работа отслеживается в выпуске # 57240. RFC 2920 «const expressions and patterns» (и его проблема с отслеживанием # 76001) также актуальны.

Для меня не сразу очевидно, как это будет работать с вашим точным примером или регулярным выражением без существенных усилий.

Комментарии:

1. я не знал, что это существует, спасибо! я немного приму ваш ответ, предполагая, что до этого не появятся другие ответы, меняющие жизнь ^-^