我正在尝试学习 Rust,特别是生命周期和智能指针,并且想知道最生锈的方法。
具体来说,假设我们正在设计一种模拟语言和“分析器”:
a=1 # each line is of form name=number|name
b=2
c=a # a is "copied" to c and should have value 1
a=4 # a and all its references should now have value 4
让我们设计一些虚假的“内存节点”抽象
代码 | 内存节点 |
---|---|
a=1 |
Node { name: "a", value: 4 } |
b=2 |
Node { name: "b", value: 2 } |
c=a |
Node { name: "c", value: 1 } |
a=4 |
Node { name: "a", value: 4 } |
注意:我们只希望存在三个内存节点,而不是像 AST 那样的四个内存节点
为了能够解析变量的值,我必须保持从名称到“内存节点”的上下文
为了保持我的分析器的 API 干净,我不想公开这个上下文。
假设我们的基础结构如下所示:
struct Root {
pub nodes: Vec<&Node>,
}
struct Node {
pub name: String,
pub value: u64,
}
struct Context {
nodes: HashMap<String, Node>,
}
impl Node {
fn new(line: &str, context: &mut Context) -> Node {
// Add self to context
// If node exists in context, update it and return the same
// return new node
}
}
但是,我们不能在 Context 和 Root 中保留 Node 的副本。
一种方法是像Rc<RefCell<Node>>
任何地方一样包装节点,这会使客户端 API 不整洁。理想情况下,我希望保持Root
包含 Vec&Node
作为公共 API。示例实现在这里https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=7ec7ecd29eea2626a11b90c829777e30
当我使用生命周期尝试此操作时,我得到一个我无法真正规避的错误 - https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=5c5054872806b94a5b3a8ad4a75c1282
它给:
error[E0499]: cannot borrow `context` as mutable more than once at a time
--> src/main.rs:49:39
|
43 | fn new(text: &str) -> Root {
| - let's call the lifetime of this reference `'1`
...
49 | let node = Node::new(row, &mut context);
| ^^^^^^^^^^^^ `context` was mutably borrowed here in the previous iteration of the loop
...
52 | Root { nodes, context }
| ----------------------- returning this value requires that `context` is borrowed for `'1`
error[E0505]: cannot move out of `context` because it is borrowed
--> src/main.rs:52:23
|
43 | fn new(text: &str) -> Root {
| - let's call the lifetime of this reference `'1`
...
49 | let node = Node::new(row, &mut context);
| ------------ borrow of `context` occurs here
...
52 | Root { nodes, context }
| --------------^^^^^^^--
| | |
| | move out of `context` occurs here
| returning this value requires that `context` is borrowed for `'1`
Some errors have detailed explanations: E0499, E0505.
For more information about an error, try `rustc --explain E0499`.
或者,如果可能的话,在不使用智能指针的情况下,还有哪些其他 Rusty 方法可以做到这一点?