我试图通过可变地借用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>
的事实,因此它应该为两个生命周期使用两个单独的生命周期电话,但我还不太想办法。
欢迎提出任何建议,我在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() {
// ...
}
}
不幸的是,我不得不使用generic associated types的不稳定功能,但是我相信这是您想要的。
我还想表达一下,对可变引用进行迭代可能不是一个好主意,如果可能的话,您应该更改程序结构。
编辑:
@pretzelhammer在评论中建议了以下可能有趣的链接:Solving the generalized streaming iterator problem without gats
关于rust - 使用生命周期参数为特征分离可变借位,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61659671/