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