简体   繁体   English

如何在 Rust 中创建自引用 AST?

[英]How to create self-referential AST in Rust?

Let's imagine we have a very simple AST for programming language with only functions and calls假设我们有一个非常简单的编程语言 AST,只有函数和调用

use std::sync::Arc;

struct Function {
    pub body: Vec<Call>
}

struct Call {
    pub function: Arc<Function> 
}

Now we want to recursively call functions:现在我们要递归调用函数:

let f = Arc::new(Function { body: vec![Call {function: f.clone()}] }) 
// Doesn't work, as we haven't created Arc yet
let mut f = Arc::new(Function { body: vec![] });
f.body.push(Call { function: f.clone() })
// Doesn't work, because Arc has immutable data

The problem can be solved using Arc<Mutex<_>> or Arc<RwLock<_>> in Call :这个问题可以在Call中使用Arc<Mutex<_>>Arc<RwLock<_>>来解决:

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

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

And then creating with:然后创建:

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

But now you need to always write f.write().unwrap() or f.read().unwrap() everywhere, even though function is mutable only on construction .但是现在您需要始终在任何地方编写f.write().unwrap()f.read().unwrap() ,即使 function仅在构造时可变。

Can you do something better than this?你能做比这更好的事吗?

Use Weak for the parent pointer.对父指针使用Weak k。 You need to do that anyway to allow for proper destruction.无论如何,您都需要这样做才能进行适当的销毁。 Then use Arc::new_cyclic() :然后使用Arc::new_cyclic()

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

struct Function {
    pub body: Vec<Call>,
}

struct Call {
    pub function: Weak<Function>,
}

let f = Arc::new_cyclic(|f| Function {
    body: vec![Call {
        function: Weak::clone(f),
    }],
});

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM