我在尝试定义和使用一个借用了 self
变化多端。
一些背景,可能会让你更容易。我正在开发一个玩具编译器,我想解决的问题是为代码节点定义一个特质,这些节点要么是语句,要么是表达式。这个特质的目的是用来遍历代码的突变(为了重写的目的)。我试图创建的抽象是一个 "代码节点",它可以有任意数量的子节点,这些子节点要么是语句,要么是表达式。事情是这样的。
// Actually these are enums with different payload types for different kinds of exprs/stmts,
// but this is not relevant.
struct Expression;
struct Statement;
trait CodeNode<'a>
where
Self::ExprIter: Iterator<Item = &'a mut Expression>,
Self::StmtIter: Iterator<Item = &'a mut Statement>,
{
type ExprIter;
type StmtIter;
fn child_exprs(&'a mut self) -> Self::ExprIter;
fn child_stmts(&'a mut self) -> Self::StmtIter;
}
这个特性将被用于很多类型(我有一个单独的类型用于不同类型的语句和表达式)。
我尝试使用的方式是。
fn process<'a>(node: &'a mut impl CodeNode<'a>) {
for _stmt in node.child_stmts() {
// ...
}
for _expr in node.child_exprs() {
// ...
}
}
这就是问题所在: Rust编译器将对 node.child_stmts
借用 node
对于 全部 辈子 'a
因此,它不允许调用到 node.child_exprs
后面在同一个函数中。下面是错误的样子。
error[E0499]: cannot borrow `*node` as mutable more than once at a time
--> src/main.rs:21:18
|
16 | fn process<'a>(node: &'a mut impl CodeNode<'a>) {
| -- lifetime `'a` defined here
17 | for _stmt in node.child_stmts() {
| ------------------
| |
| first mutable borrow occurs here
| argument requires that `*node` is borrowed for `'a`
...
21 | for _expr in node.child_exprs() {
| ^^^^ second mutable borrow occurs here
我想做的是以某种方式让编译器知道以下事实 node
实施 CodeNode<'a>
对于 任何 lifetime参数,所以它应该对twocalls使用两个独立的寿命,但我想不出办法。
欢迎提出任何建议,我对Rust的经验不多,所以可能我缺少一些更高级的解决原问题的方法。
你的一生 'a
受制于 CodeNode
所以这两个函数将以相同的寿命被调用,但你想要的是两个寿命被两个函数约束。所以为什么不做这样的事情呢。
struct Expression;
struct Statement;
trait CodeNode
{
type ExprIter<'a> : Iterator<Item = &'a mut Expression>; //unstable
type StmtIter<'a> : Iterator<Item = &'a mut Statement>; //unstable
fn child_exprs<'a>(&'a mut self) -> Self::ExprIter<'a>;
fn child_stmts<'a>(&'a mut self) -> Self::StmtIter<'a>;
}
fn process(node: &mut impl CodeNode) {
for _stmt in node.child_stmts() {
// ...
}
for _expr in node.child_exprs() {
// ...
}
}
不幸的是,我不得不使用了 通用关联类型但我相信这是你想要的。我还想表达的是,在可变引用上迭代可能不是一个好主意,如果可能的话,也许你应该改变你的程序结构。
编辑:@pretzelhammer
@pretzelhammer在评论中提出了以下链接,可能会很有趣。解决没有gats的广义流式迭代器问题