模式匹配 比 Let 更进一步
作者:Miracle
- 2025-09-23 四川
本文字数:2312 字
阅读完需:约 8 分钟

我们的目的是 解析这样的语句 let name = "zhu"
但是看到 rust 的 let (x, _) = (11, "asaas") 我们很眼红
是我们的设计开始就要做的很完整。所以我们用一个 pattern 来解析赋值语句。为以后的这种当然可以做的很简单,先支持一个标识符的。我们先用 pattern 来做,以后还可以做以后的 match。
我们定义 基础的 Pattern 枚举如下
#[derive(Debug, Clone)]pub enum Pattern { Wildcard, // _ Ident(SmolStr), Literal(Dynamic), // "abc", 123, true Tuple(Vec<Pattern>), // (a, b, c) List { elems: Vec<Pattern>, has_rest: bool }, // [a, b, ..]}复制代码
有一个基础方法 判断 Pattern 是否可以作为左值 所谓的左值就是可以位于等式的左边 也就是可以被赋值的值
impl Pattern { pub fn is_valid_lvalue(&self) -> bool { match self { Pattern::Ident(_) | Pattern::Wildcard => true, Pattern::Tuple(elems) => elems.iter().all(|p| p.is_valid_lvalue()), Pattern::List { elems, .. } => elems.iter().all(|p| p.is_valid_lvalue()), Pattern::Literal(_) => false, } }}
复制代码
这个时候我们突然发现 模式的赋值怎么办
比如说
vec 是一个数组
vec[10] = "zzz"
这是一个赋值语句 我们可以用 Pattern 来映射 但是 目前的 Pattern 是不行的 索引我们要支持 A.b 或者 X[100] 形态的 Pattern
而且关键的 能递归! x[100].y[1024] 可以支持 所以我们修改 Pattern 定义如下
最新的定义如下
pub enum Pattern { Wildcard, // _ Ident(SmolStr), Literal(Dynamic), // "abc", 123, true Tuple(Vec<Pattern>), // (a, b, c) List { elems: Vec<Pattern>, has_rest: bool }, // [a, b, ..] Member(Box<Pattern>, SmolStr), //x.y Idx(Box<Pattern>, Expr), // x[y]}
impl Pattern { pub fn is_valid_lvalue(&self) -> bool { match self { Self::Ident(_) | Self::Wildcard => true, Self::Tuple(elems) => elems.iter().all(|p| p.is_valid_lvalue()), Self::List { elems, .. } => elems.iter().all(|p| p.is_valid_lvalue()), Self::Literal(_) => false, Self::Member(x, _) => x.is_valid_lvalue(), Self::Idx(x, _) => x.is_valid_lvalue(), } }}复制代码
增加解析后缀的函数
fn suffix_parser<'a>() -> impl Parser<'a, &'a str, Vec<Box<dyn Fn(Pattern) -> Pattern>>, Extra<'a>> + Clone { let member = just('.').ignore_then(super::ident_parser()).map(|field: SmolStr| Box::new(move |base| Pattern::Member(Box::new(base), field.clone())) as Box<dyn Fn(Pattern) -> Pattern>);
let index = just('[').ignore_then(expr_parser()).then_ignore(just(']')).map(|idx| Box::new(move |base| Pattern::Idx(Box::new(base), idx.clone())) as Box<dyn Fn(Pattern) -> Pattern>); choice((member, index)).repeated().collect()}
复制代码
这里的后缀和在你的后缀和表达式里面的后缀。是完全不同的两个概念。因为这个模式匹配有很多。不同的限制措施。所以我们这里面不去复用,而且这个代码不是多复杂。所以我们不去复用。这个一眼就能看明白 我们就不多做解释了
use super::{ident_parser, rust_ws, literal::{number_parser, string_parser, const_value_parser}};pub(crate) fn pattern_parser<'a>() -> impl Parser<'a, &'a str, Pattern, Extra<'a>> + Clone { recursive::<'a, 'a, &'a str, Pattern, Extra<'a>, _, _>(|pat| { let ident_pat = just("mut").padded().or_not() .then(ident_parser().padded_by(rust_ws())).map(|(_mut, name)| Pattern::Ident(name)) .padded_by(rust_ws()).labelled("identifier pattern");
let wild_pat = just('_').padded_by(rust_ws()).to(Pattern::Wildcard).labelled("wildcard pattern"); let lit_pat = choice((number_parser().map(|n| Pattern::Literal(n)), string_parser().map(|s| Pattern::Literal(Dynamic::from(s))), const_value_parser().map(|c| Pattern::Literal(c)))).padded_by(rust_ws()).labelled("literal pattern");
let tuple_pat = pat.clone().separated_by(just(',').padded_by(rust_ws())).collect::<Vec<Pattern>>().delimited_by(just('(') .padded_by(rust_ws()), just(')').padded_by(rust_ws())).map(Pattern::Tuple).labelled("tuple pattern");
let list_pat = pat.clone().separated_by(just(',').padded_by(rust_ws())).allow_trailing().collect::<Vec<Pattern>>() .then(just("..").padded_by(rust_ws()).or_not()).map(|(elems, rest)| Pattern::List { elems, has_rest: rest.is_some() }) .delimited_by(just('[').padded_by(rust_ws()), just(']').padded_by(rust_ws())).labelled("list pattern"); choice((wild_pat, lit_pat, ident_pat, tuple_pat, list_pat)).boxed().then(suffix_parser()).map_with(|(base, suffix), _| suffix.into_iter().fold(base, |acc, f| f(acc))) })}复制代码
划线
评论
复制
发布于: 刚刚阅读数: 3
Miracle
关注
三十年资深码农 2019-10-25 加入
还未添加个人简介







评论