每当我觉得我有点惯用的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;
,对我来说,这是最直观的。另外,其他两个错误表明我有借用/引用错误。我做错了什么?
答案 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.ods
和Some(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