Rust如何在编译期将字符串转为char数组用于模式匹配
解决方案
完全可以实现,以下是两种常用的编译期实现方案:
方案1:const 函数实现(Rust 1.70+ 支持)
首先定义编译期转换的const函数,生成的固定长度char数组可直接用于模式匹配:
const fn str_to_char_arr<const N: usize>(s: &str) -> [char; N] { let mut arr = ['\0'; N]; let mut chars = s.chars(); let mut idx = 0; while idx < N { match chars.next() { Some(c) => arr[idx] = c, None => panic!("字符串长度与数组长度不匹配") } idx += 1; } assert!(chars.next().is_none(), "字符串长度超过数组容量"); arr } // 提前定义匹配用的常量,可直接放入模式中 const LET_PAT: [char; 3] = str_to_char_arr("let"); const TRUE_PAT: [char; 4] = str_to_char_arr("true");
使用时直接在match分支引用常量即可:
match &source[..] { // 匹配let前缀,剩余字符存入rest [LET_PAT @ .., rest @ ..] => { /* 处理逻辑 */ }, [TRUE_PAT @ .., rest @ ..] => { /* 处理逻辑 */ }, _ => { /* 其他情况 */ } }
方案2:声明式宏实现
如果不想提前定义大量常量,可以用宏直接在匹配分支生成对应的const数组:
macro_rules! char_pat { ($s:literal) => {{ const LEN: usize = $s.len(); const ARR: [char; LEN] = const { let mut arr = ['\0'; LEN]; let mut chars = $s.chars(); let mut idx = 0; while idx < LEN { arr[idx] = chars.next().unwrap(); idx += 1; } arr }; ARR }}; }
使用时直接在模式中嵌入宏调用:
match &source[..] { [char_pat!("let") @ .., rest @ ..] => {}, [char_pat!("true") @ .., rest @ ..] => {}, _ => {} }
补充:更简洁的非模式匹配方案
如果不需要严格使用模式匹配语法,也可以通过守卫函数实现相同效果,可读性更高且无需处理数组长度问题:
/// 检查char切片是否以指定字符串为前缀 fn starts_with(s: &[char], prefix: &str) -> bool { s.len() >= prefix.len() && s.iter().zip(prefix.chars()).all(|(a, b)| *a == b) } // 使用示例 match &source[..] { s if starts_with(s, "let") => {}, s if starts_with(s, "true") => {}, _ => {} }
该实现可被LLVM完全优化为和手动匹配数组等价的机器码,无运行时开销。
内容的提问来源于stack exchange,提问作者clubby789
相关产品推荐
相关产品推荐

