如何在循环中使用可变状态?

How to use mutable state in a loop?

循环:

impl State {    
    pub fn exec(&mut self) -> Vec<(&[u8], SocketAddr)> {
        vec!()
    }
}

fn main_loop(mut state: State) {
    let mut packets = Vec::<(&[u8], SocketAddr)>::new();
    loop {
        let new = state.exec();
        packets.extend(new);
    }
}

报错:

error[E0499]: cannot borrow `state` as mutable more than once at a time
  --> src/main.rs:93:14
   |
93 |             let new = state.exec();
   |                       ^^^^^ `state` was mutably borrowed here in the previous iteration of the loop

然而,如果我注释掉 packets.extend(new); 行,则没有错误。

认为问题是返回的vector属于state,好像new在循环迭代之前被丢弃了,没问题。我很高兴复制返回的矢量,如果这样可以解决问题的话。

我预计将 .clone() 添加到 newstate.exec() 会修复它,但它没有。

有解决这个问题的简单方法吗?

或者我是否需要以不同的方式构造单线程应用程序状态?

一个解决方案是:

impl State {    
    pub fn exec(&mut self) -> Vec<(Vec<u8>, SocketAddr)> {
        vec!()
    }
}

fn main_loop(mut state: State) {
    let mut packets = Vec::<(Vec<u8>, SocketAddr)>::new();
    loop {
        let new = state.exec();
        packets.extend(new);
    }
}

我不确定这是不是最好的解决方案,所以我会暂时搁置这个问题。

pub fn exec(&mut self) -> Vec<(&[u8], SocketAddr)>

让我们加入 implicit lifetimes

pub fn exec<'a>(&'a mut self) -> Vec<(&'a [u8], SocketAddr)>

因此返回的切片必须具有与可变借用 相同的 生命周期。现在,您将如何处理返回的切片?

let new = state.exec();
packets.extend(new);

我们将其存储在packets中。所以 state 的借用必须至少持续到 packets 的类型,这就是整个函数。因此,从循环的第一次迭代到函数的最后,我们再也不能借用 state,因为可变借用一直持续到函数结束。

要问自己的第一个问题是:您真的需要可变借用吗?如果你可以下降到 &self,那么就这样做,你的问题就解决了。否则,您将需要以某种方式重组事物。类型 &[u8] 本质上是无主的。这是对 其他人的 数据的引用。如果您获取该数据的唯一方法是通过 &mut self,那么您将永远无法按照您想要的方式循环。因此,要克隆数据,您需要使用 to_vec,它将 &[u8] 变成 Vec<u8>(您的类型签名必须更改以反映这一点)。

只需更改函数签名,使返回的 &[u8] 不借用 *self 即可编译示例代码:

    pub fn exec<'a>(&mut self) -> Vec<(&'a [u8], SocketAddr)> {
        vec![]
    }

请注意 'a 是一个自由生命周期参数,因此调用者可以在那里提供任何内容(包括 'static)和任何引用 exec returns 必须满足调用者提供的生命周期。实际上,这意味着 Vec 只能包含 'static 引用,因为 'static 是唯一的生命周期,它是所有其他生命周期的子类型。

这不太可能是您想要的。但是,它可能是,或者 [u8] 可能是从其他参数(而不是 *self)借来的,或者是从 *self 中包含的引用重新借来的。这表明,只需更改签名以更准确地表示输入和输出之间的生命周期关系,有时就可以在不进行任何其他更改的情况下修复此类错误。