在编译时将 String 转换为 Vec<char> 以进行模式匹配
Convert String to Vec<char> at compile time for pattern matching
我正在用 Rust 编写一个解析器,我正在从 Vec<char>
创建令牌。目前,我的代码看起来像
match &source[..] {
['l', 'e', 't', ..] => ...,
['t', 'r', 'u', 'e', ..] => ...,
_ => ...
}
显然,这比我想要的要冗长得多,而且不容易阅读。有什么方法可以在编译时将 "let"
转换为 ['l', 'e', 't']
(使用宏或 const 函数)以便像这样对其进行模式匹配?
我不认为你可以使用 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_macro
crate。
我正在用 Rust 编写一个解析器,我正在从 Vec<char>
创建令牌。目前,我的代码看起来像
match &source[..] {
['l', 'e', 't', ..] => ...,
['t', 'r', 'u', 'e', ..] => ...,
_ => ...
}
显然,这比我想要的要冗长得多,而且不容易阅读。有什么方法可以在编译时将 "let"
转换为 ['l', 'e', 't']
(使用宏或 const 函数)以便像这样对其进行模式匹配?
我不认为你可以使用 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_macro
crate。