使用生命周期参数分离特征的可变借用
Separating mutable borrows for trait with lifetime parameter
我 运行 在尝试通过可变借用 self
的方法定义和使用特征时遇到了问题。
一些可能使它更容易的上下文:我正在开发一个玩具编译器,我试图解决的问题是为代码节点定义一个特征,这些节点可以是语句也可以是表达式。该特征旨在用于可变地遍历代码(用于重写目的)。我试图创建的抽象是一个 "code node",它可能有任意数量的子项,这些子项要么是语句,要么是表达式。事情是这样的:
// 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
为 any 生命周期参数实现 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 在评论中提出以下 link 这可能很有趣:Solving the generalized streaming iterator problem without gats
我 运行 在尝试通过可变借用 self
的方法定义和使用特征时遇到了问题。
一些可能使它更容易的上下文:我正在开发一个玩具编译器,我试图解决的问题是为代码节点定义一个特征,这些节点可以是语句也可以是表达式。该特征旨在用于可变地遍历代码(用于重写目的)。我试图创建的抽象是一个 "code node",它可能有任意数量的子项,这些子项要么是语句,要么是表达式。事情是这样的:
// 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
为 any 生命周期参数实现 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 在评论中提出以下 link 这可能很有趣:Solving the generalized streaming iterator problem without gats