分离带寿命参数的性状的可突变借代。

问题描述 投票:1回答:1

我在尝试定义和使用一个借用了 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的经验不多,所以可能我缺少一些更高级的解决原问题的方法。

rust traits lifetime borrow-checker borrowing
1个回答
1
投票

你的一生 '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的广义流式迭代器问题

© www.soinside.com 2019 - 2024. All rights reserved.