Rust 迭代并从选项向量中获取

Rust 迭代并从选项向量中获取,rust,Rust,每次我觉得自己已经掌握了一点惯用的锈迹,它又一次击败了我。在本例中,我得到了一个结构状态,其中包含一个名为ods的Vec,其中Dude是一个如下所示的结构: pub struct Dude { pub capacity: i32, pub status: DudeStatus, } 我想做的是在State上定义一个函数/方法,该函数/方法迭代ods。如果给定索引中存在Dude(即,如果ods[i]==Some(Dude)),则将其容量减少一,如果这导致容量==0,则从ods中删

每次我觉得自己已经掌握了一点惯用的锈迹,它又一次击败了我。在本例中,我得到了一个结构
状态
,其中包含一个名为
ods
Vec
,其中
Dude
是一个如下所示的结构:

pub struct Dude {
    pub capacity: i32,
    pub status: DudeStatus,
}
我想做的是在
State
上定义一个函数/方法,该函数/方法迭代
ods
。如果给定索引中存在
Dude
(即,如果ods[i]==Some(Dude)),则将其容量减少一,如果这导致
容量==0
,则从
ods
中删除
Dude
。不幸的是,我似乎遇到了类型推断和/或所有权问题。以下是我的尝试:

fn tick(&mut self) {
    for d in &self.ods {
        match d {
            Some(du) => {
                du.capacity -= 1;
                if du.capacity == 0 {
                    d.take();
                }
            }
            None => {}
        };
    }
}
但是,这会产生3个编译错误:

src/state.rs:40:18: 40:26 error: mismatched types:
 expected `&std::option::Option<dude::Dude>`,
 found `std::option::Option<_>`
 (expected &-ptr,
 found enum `std::option::Option`) [E0308]
src/state.rs:40                  Some(du) => {
                                 ^~~~~~~~

src/state.rs:46:18: 46:22 error: mismatched types:
 expected `&std::option::Option<dude::Dude>`,
 found `std::option::Option<_>`
 (expected &-ptr,
 found enum `std::option::Option`) [E0308]
src/state.rs:46                  None         => {}

src/state.rs:41:22: 41:32 error: the type of this value must be known in this context
src/state.rs:41                      du.capacity -=1;
src/state.rs:40:18:40:26错误:不匹配的类型:
应为“&std::option::option”,
找到'std::option::option'`
(预期和-ptr,
找到枚举'std::option::option`)[E0308]
src/state.rs:40部分(du)=>{
^~~~~~~~
src/state.rs:46:18:46:22错误:不匹配的类型:
应为“&std::option::option”,
找到'std::option::option'`
(预期和-ptr,
找到枚举'std::option::option`)[E0308]
src/state.rs:46无=>{}
src/state.rs:41:22:41:32错误:此上下文中必须知道此值的类型
src/state.rs:41 du.capacity-=1;
第三个错误在概念上很容易理解,但我不确定应该在哪里注释类型。类型归属目前是一个实验性功能,因此我不能使用
match d:Option
,这对我来说是最直观的。另外两个错误表明我有借用/引用错误。我做错了什么?

fn tick(&mut self) {
    for d in &self.ods {
这将给出不可变的
d
s。因为您想要修改
d
,所以应该在
&mut self.ods
上迭代

        match d {
            Some(du) => {
请注意,
d
是一个引用。您应该遵从它
match*d
。并且您希望通过可变引用(
Some(ref mut du)=>
)捕获
du
),以便将更改传播回原始存储

由于
None
arm没有执行任何操作,您可以使用
if let
而不是
match
来保存缩进级别

                if du.capacity == 0 {
                    d.take();
                }
在我们解决了上述两个问题后,借用检查器将在此处投诉。这是意料之中的,因为从
d
借用
du
仍然有效,但您现在尝试销毁
d
。我们需要调用
.take()
匹配之外
。我个人会添加一个标志,指示是否需要将
d
置零。请注意,由于您没有使用结果,只需调用
*d=None
就足够了


最终结果:

fn tick(&mut self) {
    for d in &mut self.ods {
        let mut should_nullify = false;
        if let Some(ref mut du) = *d {
            du.capacity -= 1;
            if du.capacity == 0 {
                should_nullify = true;
            }
        }
        if should_nullify {
            *d = None;
        }
    }
}

以下是我用来填写您未提供的方面的代码:

struct Dude {
    pub capacity: i32,
}

struct State {
    ods: Vec<Option<Dude>>,
}

impl State {
    fn tick(&mut self) {
        for d in &self.ods {
            match d {
                Some(du) => {
                    du.capacity -= 1;
                    if du.capacity == 0 {
                        d.take();
                    }
                }
                None => {}
            };
        }
    }
}

fn main() {}
如果要从
Vec
中删除,也可以使用
retain

fn tick(&mut self) {
    for d in &mut self.ods {
        if let Some(ref mut du) = *d {
            du.capacity -= 1;
        }
    }

    self.ods.retain(|d| {
        d.as_ref().map_or(false, |du| {
            du.capacity != 0
        })
    })
}

这两个答案都令人难以置信。我正在给你打勾,让你一步一步地解决我的愚蠢错误。谢谢@Shepmaster!我怀疑我的问题的一部分来自于在迭代过程中对vec的变异(将某些()更改为无).我甚至没有想到,当我还在引用期权的价值时,我正在对期权进行变异!
fn tick(&mut self) {
    for d in &mut self.ods {
        let remove = match *d {
            Some(ref mut du) => {
                du.capacity -= 1;
                du.capacity != 0
            }
            None => false,
        };

        if remove {
            d.take();
        }
    }
}
fn tick(&mut self) {
    for d in &mut self.ods {
        if let Some(ref mut du) = *d {
            du.capacity -= 1;
        }
    }

    self.ods.retain(|d| {
        d.as_ref().map_or(false, |du| {
            du.capacity != 0
        })
    })
}