首页 > 解决方案 > 将字符串转换为 Vec在编译时进行模式匹配

问题描述

我正在用 Rust 编写解析器,并且正在从Vec<char>. 目前,我的代码看起来像

match &source[..] {
    ['l', 'e', 't', ..] => ...,
    ['t', 'r', 'u', 'e', ..] => ...,
    _ => ...
}

显然,这比我想要的要冗长得多,而且不容易阅读。有什么方法可以在编译时转换"let"['l', 'e', 't'](使用宏或 const 函数)以便像这样对其进行模式匹配?

标签: rustpattern-matching

解决方案


我不认为你可以使用 Rust 标准库中的宏来做到这一点,但你可以编写自己的宏:

use proc_macro::{TokenStream, TokenTree, Group, Delimiter, Punct, Literal, Spacing};
use syn::{parse_macro_input, LitStr};

#[proc_macro]
pub fn charize(input: TokenStream) -> TokenStream {
    // some stuff for later
    let comma_token = TokenTree::Punct(Punct::new(',', Spacing::Alone));
    let rest_token_iterator = std::iter::once(TokenTree::Punct(Punct::new('.', Spacing::Joint))).chain(std::iter::once(TokenTree::Punct(Punct::new('.', Spacing::Alone))));
    
    
    let string_to_charize: String = parse_macro_input!(input as LitStr).value();
    
    let char_tokens_iterator = string_to_charize.chars().map(|char| TokenTree::Literal(Literal::character(char)));
    // if you are on nightly, Iterator::intersperse() is much cleaner than this (https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.intersperse)
    let char_tokens_interspersed_iterator = char_tokens_iterator.map(|token| [comma_token.clone(), token]).flatten().skip(1);
    let char_tokens_interspersed_with_rest_iterator = char_tokens_interspersed_iterator.chain(std::iter::once(comma_token.clone())).chain(rest_token_iterator);
    
    std::iter::once(TokenTree::Group(Group::new(Delimiter::Bracket, char_tokens_interspersed_with_rest_iterator.collect()))).collect()
    
}

宏在行动:

match &['d', 'e', 'm', 'o', 'n', 's', 't', 'r', 'a', 't', 'i', 'o', 'n'][..] {
    charize!("doesn't match") => println!("Does not match"),
    charize!("demo") => println!("It works"),
    charize!("also doesn't match") => println!("Does not match"),
    _ => panic!("Does not match")
}

请注意,这是一个程序宏,因此必须存在于proc_macrocrate 中


推荐阅读