Vector 在没有内存分配的情况下,我如何变异并有选择地从vec中删除元素?

Vector 在没有内存分配的情况下,我如何变异并有选择地从vec中删除元素?,vector,rust,borrowing,Vector,Rust,Borrowing,我有一个Player结构,它包含一个效果实例的vec。我想迭代这个vec,减少每个效果的剩余时间,然后删除剩余时间为零的任何效果。到现在为止,一直都还不错。但是,对于任何移除的效果,我还希望在销毁效果实例之前将其传递给播放器的undo_effect()方法 这是游戏循环的一部分,因此如果可能的话,我希望在没有任何额外内存分配的情况下执行此操作 我尝试过使用一个简单的for循环以及迭代器、drain、retain和filter,但我一直遇到self(玩家)会被多次可变借用的问题,因为修改self.

我有一个Player结构,它包含一个效果实例的vec。我想迭代这个vec,减少每个效果的剩余时间,然后删除剩余时间为零的任何效果。到现在为止,一直都还不错。但是,对于任何移除的效果,我还希望在销毁效果实例之前将其传递给播放器的undo_effect()方法

这是游戏循环的一部分,因此如果可能的话,我希望在没有任何额外内存分配的情况下执行此操作

我尝试过使用一个简单的for循环以及迭代器、drain、retain和filter,但我一直遇到self(玩家)会被多次可变借用的问题,因为修改self.effects需要可变借用,就像undo_effect()方法一样。《夜间》中的drain_filter()在这里看起来很有用,但它是在2017年首次提出的,所以我不会屏住呼吸

编译的一种方法(见下文)是使用两个向量,并在每一帧上交替使用。元素从vec 1弹出(),并根据需要推送()到vec 2或传递到undo_effect()。在下一个游戏循环迭代中,方向是相反的。由于每个vec都不会收缩,因此只有当它们比以前更大时,才会进行分配。 我开始将其抽象为自己的结构,但想检查是否有更好(或更简单)的方法

这个不能编译。调用self.undo_effect()会将self作为可变项借用两次

struct播放器{
效果:Vec
}
impl播放器{
fn更新(&mut self,增量时间:f32){
用于在多个自我影响中的效果(&M){
影响。剩余-=增量时间;

如果effect.remaining如果我理解正确,您有两个问题:

  • 如何将
    Vec
    拆分为两个
    Vec
    s(一个满足预测,另一个不满足预测)
  • 有没有可能不增加内存开销

  • 有多种方法可以将Vec拆分为两个(或多个)

    • 您可以使用它,它将为您提供两个不同的迭代器,可以进一步使用它们
    • 有一个不稳定的函数,其作用与此相同,但它位于
      Vec
      本身
    • 使用(或
      splitn_mut
      )将Vec/切片拆分为
      n
      (在您的情况下为2个)迭代器
    根据您想要做的事情,所有解决方案都适用且易于使用


    是否可能没有内存开销?不使用上述解决方案,因为您需要创建第二个
    Vec
    ,该Vec可以保存筛选的项目。但有一个解决方案,即您可以“排序”Vec,其中前半部分将包含满足谓词的所有项目(例如未过期)第二部分将使谓词失败(过期)。您只需要计算满足谓词的项的数量


    然后,您可以使用(或
    split_at_mut
    )将Vec/切片拆分为两个不同的切片。之后,您可以将Vec调整为良好项目的长度,其他项目将被删除。

    如果我理解正确,您有两个问题:

  • 如何将
    Vec
    拆分为两个
    Vec
    s(一个满足预测,另一个不满足预测)
  • 有没有可能不增加内存开销

  • 有多种方法可以将Vec拆分为两个(或多个)

    • 您可以使用它,它将为您提供两个不同的迭代器,可以进一步使用它们
    • 有一个不稳定的函数,其作用与此相同,但它位于
      Vec
      本身
    • 使用(或
      splitn_mut
      )将Vec/切片拆分为
      n
      (在您的情况下为2个)迭代器
    根据您想要做的事情,所有解决方案都适用且易于使用


    是否可能没有内存开销?不使用上述解决方案,因为您需要创建第二个
    Vec
    ,该Vec可以保存筛选的项目。但有一个解决方案,即您可以“排序”Vec,其中前半部分将包含满足谓词的所有项目(例如未过期)第二部分将使谓词失败(过期)。您只需要计算满足谓词的项的数量


    然后,您可以使用(或
    split_at_mut
    )将Vec/切片分割为两个不同的切片。之后,您可以将Vec调整为良好项目的长度,其他项目将被删除。

    主要问题是您借用了一个字段(
    效果
    )在借用此字段时,尝试调用
    undo_effect
    。如您所述,这不起作用

    您已经意识到可以处理两个向量,但实际上只能处理一个(永久)向量:

    struct播放器{
    效果:Vec
    }
    impl播放器{
    fn更新(&mut self,增量时间:f32){
    用于在多个自我影响中的效果(&M){
    影响。剩余-=增量时间;
    
    如果effect.remaining,主要问题是您正在借用
    Player
    的一个字段(
    effects
    ),并试图在借用该字段时调用
    undo\u effect
    。如您所述,这不起作用

    您已经意识到可以处理两个向量,但实际上只能处理一个(永久)向量:

    struct播放器{
    效果:Vec
    }
    impl播放器{
    fn更新(&mut self,增量时间:f32){
    用于在多个自我影响中的效果(&M){
    影响。剩余-=增量时间;
    如果有效剩余最好的答案是

    [O] 对索引向量排序,在数据向量中创建两个迭代器,一个用于读取,一个用于写入。将写入迭代器初始化为要删除的第一个元素,将读取迭代器初始化为要删除的第一个元素之外的元素。然后在循环的每个步骤中,将迭代器递增到下一个值(写入),而不递增到下一个值
    struct Player {
        effects: Vec<Effect>
    }
    
    impl Player {
        fn update(&mut self, delta_time: f32) {
            for effect in &mut self.effects {
                effect.remaining -= delta_time;
                if effect.remaining <= 0.0 {
                    effect.active = false;
                }
            }
    
            //  Temporarily remove effects from Player.
            let mut effects = std::mem::replace(&mut self.effects, vec!());
    
            //  Call Player::undo_effects (no outstanding borrows).
            //  `drain_filter` could also be used, for better efficiency.
            for effect in effects.iter_mut().filter(|e| !e.active) {
                self.undo_effect(effect);
            }
    
            //  Restore effects
            self.effects = effects;
    
            self.effects.retain(|e| e.active);
        }
    }