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

如何在Rust中创建自引用抽象语法树(AST)?

解决Rust中递归AST节点的构造问题

问题背景

我们有一个极简编程语言的AST结构,仅包含函数和调用定义:

use std::sync::Arc;

struct Function {
    pub body: Vec<Call>
}

struct Call {
    pub function: Arc<Function> 
}

尝试实现函数递归调用时,常规写法都会失败:

  1. 直接初始化时无法引用未创建的Arc:
let f = Arc::new(Function { body: vec![Call {function: f.clone()}] }) 
// 报错:使用了未初始化的变量f
  1. 先创建空Arc再修改内容也不可行,因为Arc包裹的数据默认不可变:
let mut f = Arc::new(Function { body: vec![] });
f.body.push(Call { function: f.clone() })
// 报错:无法修改Arc中的不可变数据

现有方案是用Arc<RwLock<_>>或Arc<Mutex<_>>包裹Function:

use std::sync::{Arc, RwLock};

struct Call {
    pub function: Arc<RwLock<Function>> 
}

创建递归实例的代码如下:

let f = Arc::new(RwLock::new(Function { body: vec![] }));
f.write().unwrap().body.push(Call { function: f.clone() })

但这个方案的痛点很明显:即使仅在构造阶段需要可变操作,后续所有访问都必须通过read()/write()加锁解锁,不仅代码冗余,还会带来不必要的运行时开销。

更优解决方案:利用一次性/惰性初始化工具

方案1:使用OnceCell实现延迟初始化

借助OnceCell的一次性初始化特性,先创建空的Arc<OnceCell<Function>>,再填充内容并建立递归引用:

use std::sync::{Arc, OnceCell};

struct Function {
    pub body: Vec<Call>
}

struct Call {
    pub function: Arc<OnceCell<Function>> 
}

// 创建递归函数实例
let f = Arc::new(OnceCell::new());
f.set(Function {
    body: vec![Call { function: f.clone() }]
}).unwrap();

后续访问时,只需调用get().unwrap()即可获取不可变引用,无需每次加锁:

// 访问函数体
let function_body = &f.get().unwrap().body;

方案2:使用LazyLock(Rust 1.63+)实现惰性初始化

如果你的Rust版本在1.63及以上,可以用标准库的LazyLock(原社区库lazy_static的官方实现),写法更简洁:

use std::sync::{Arc, LazyLock};

struct Function {
    pub body: Vec<Call>
}

struct Call {
    pub function: Arc<LazyLock<Function>> 
}

// 创建递归函数实例
let f = Arc::new(LazyLock::new(|| {
    Function {
        body: vec![Call { function: f.clone() }]
    }
}));

访问时直接通过&*f即可获取Function的引用,无需额外调用:

let function_body = &(*f).body;

方案优势

  • 仅在构造阶段处理可变逻辑,后续访问完全是无锁的不可变引用,性能更优
  • 避免了RwLock/Mutex带来的冗余代码和运行时开销
  • 保证数据安全性:OnceCell和LazyLock都确保初始化只执行一次,且初始化完成后数据不可变

内容的提问来源于stack exchange,提问作者gavrilikhin.d

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 11:25:34