写点什么

模式匹配 比 Let 更进一步

作者:Miracle
  • 2025-09-23
    四川
  • 本文字数:2312 字

    阅读完需:约 8 分钟

模式匹配 比 Let 更进一步

我们的目的是 解析这样的语句 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))) })}
复制代码


用户头像

Miracle

关注

三十年资深码农 2019-10-25 加入

还未添加个人简介

评论

发布
暂无评论
模式匹配 比 Let 更进一步_Miracle_InfoQ写作社区