You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Rust中递归类型结合Rc的嵌套模式匹配可行性及求导程序移植问题

解决Rust中Rc包裹递归表达式的嵌套模式匹配问题

你猜得没错,这确实是Rust模式匹配的一个限制——当前稳定版里,没办法直接在模式里对Rc这类智能指针做嵌套的解引用匹配。你代码里的(f, Add(Int(n), g))这类模式之所以总是失败,是因为f和g都是Rc<Expr2>类型,而Add是Expr2的枚举变体,Rust不会自动帮你穿透Rc去匹配内部的枚举值。

怎么解决这个问题?

最直接的办法是手动解引用Rc之后再做模式匹配。因为Rc是共享所有权的智能指针,我们只需要获取内部值的不可变引用就能做匹配(毕竟表达式化简是只读操作),可以用&*rc或者rc.as_ref()来拿到内部Expr2的引用。

比如修改你的add函数,改成这样:

fn add(f: Expr, g: Expr) -> Expr {
    match (&*f, &*g) {
        (Int(m), Int(n)) => Rc::new(Int(m + n)),
        (Int(0), _) => g,
        (_, Int(n)) => add(g, f),
        (_, Add(Int(n), inner_g)) => add(Rc::new(Int(*n)), add(f, Rc::clone(inner_g))),
        (Add(inner_f, inner_g), _) => add(Rc::clone(inner_f), add(Rc::clone(inner_g), g)),
        _ => Rc::new(Add(f, g)),
    }
}

这里要注意几点:

  • 匹配时用&*f拿到Expr2的不可变引用,这样就能匹配到Int、Add这些变体了
  • 构造新的Expr时要用Rc::new把枚举值包起来
  • 对于需要复用的内部表达式节点,用Rc::clone来增加引用计数,避免不必要的内存复制

同理,你的mul、pow、d等函数都需要做类似的修改,把对Expr的直接匹配改成对&*Expr的匹配。

关于你提到的“box语法”

你说的那个规划中的模式匹配解引用语法(比如box Add(...))确实存在,但它目前只针对Box类型,而且还处于不稳定状态(需要启用box_patterns特性)。更关键的是,它并不支持Rc,所以哪怕这个特性稳定了,也帮不上你当前的场景。

顺便提几个代码里的小问题

除了模式匹配的问题,你的代码还有几个编译错误需要修正:

  1. d函数里的Var(y)分支:你直接返回了字符串x或y,但函数返回值是Expr,应该改成Rc::new(Var(x.clone()))或者Rc::new(Var(y))
  2. string_of_expr函数:你只调用了count(f).to_string()但没有返回它,应该改成count(f).to_string()作为返回值
  3. nest函数:你写了f(x),但f是Expr类型(数据结构)不是函数,应该把nest的参数改成接受一个函数,比如:
    fn nest(n: i32, func: impl Fn(Expr) -> Expr, x: Expr) -> Expr {
        if n == 0 { x } else { nest(n - 1, func, func(x)) }
    }
    
  4. main函数里的x:你直接用字符串"x"调用pow,但pow需要Expr类型,应该改成let x = Rc::new(Var("x".to_string()));,再传递给pow

内容的提问来源于stack exchange,提问作者J D

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 03:38:55