迭代并从选项向量中获取

时间:2016-06-13 17:25:03

标签: rust

每当我觉得我有点惯用的Rust时,它会再次击败我。在这种情况下,我有一个结构State,其中包含一个名为Vec<Option<Dude>>的{​​{1}},其中ods是一个如下所示的结构:< / p>

Dude

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

ods

但是,这会产生3个编译错误:

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

第三个错误很容易从概念上理解,但我不确定我应该在哪里注释该类型。类型归属目前是一个实验性功能,所以我不能使用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; ,对我来说,这是最直观的。另外,其他两个错误表明我有借用/引用错误。我做错了什么?

2 个答案:

答案 0 :(得分:5)

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

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() {}

检出第一个错误:

error: mismatched types:
 expected `&core::option::Option<Dude>`,
    found `core::option::Option<_>`
(expected &-ptr,
    found enum `core::option::Option`) [E0308]

                 Some(du) => {
                 ^~~~~~~~

match语句正在寻找匹配臂为&Option<Dude,但该模式代表Option<_>(“尚未确定类型的选项”)。如果您在&Some上将其更改为*d或(更具惯用地)匹配,则该错误将消失。

然后你遇到了一个不可逆转的问题,因此需要修复(for d in &mut self.odsSome(mut du))。

然后您试图将矢量移出Some模式,因此您需要Some(ref mut du)

然后你遇到了真正的问题:你试图在引用它的内部结构时改变Option。这是无效的,会导致内存安全问题!

相反,拆分递减计数和删除值的概念:

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();
        }
    }
}

如果您想从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
        })
    })
}

答案 1 :(得分:4)

  Action := HandleReconcileError(DataSet, UpdateKind, E);
  if(Action = raMerge)then
  begin
    fIsMerged := true;
  end;

这将提供不可变的fn tick(&mut self) { for d in &self.ods { 。由于您要修改d,因此您应该在d上进行迭代。

&mut self.ods

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

由于Some(ref mut du) =>手臂无效,您可以使用None代替if let来保存缩进级别。

match

在我们解决了上述两个问题之后,借阅检查员会在这里投诉。这是预期的,因为从 if du.capacity == 0 { d.take(); } 借用du仍然有效,但您现在尝试销毁d。我们需要在d之外拨打.take()。我个人会添加一个标志来表明我们是否需要取消match。请注意,由于您没有使用结果,只需调用d即可。

最终结果:

*d = None