我已编写此代码用于在州之间转换,但如果未通过借阅检查程序:
struct State {
// ...
}
impl State {
fn next(self) -> (Self, u32) {
// ...
}
}
struct StateHolder {
state: State
}
impl StateHolder {
fn next_value(&mut self) -> u32 {
// ERROR: Cannot move out of borrowed context
let (new_state, byproduct) = self.state.next();
self.state = new_state;
return byproduct;
}
}
这似乎是我通常使用std::mem::replace
的情况,但由于new_state
的值取决于旧状态,因此它只是在这里工作。
我知道我可以通过State
实施Clone
并执行此操作来完成这项工作:
fn next_value(&mut self) -> u32 {
let (new_state, byproduct) = self.state.clone().next();
self.state = new_state;
return byproduct;
}
但我不想做那样的不必要的副本,或者需要State
来实现Clone
。 (我认为编译器会在这种情况下优化副本,但我不想依赖它。)
我也知道在不安全的Rust中有很多方法可以做到这一点,但对于这种简单且明显安全的模式来说,这似乎有些过分。
有没有办法在安全的Rust中写这个,没有不必要的复制?
答案 0 :(得分:6)
最简单的方法:
fn next(&mut self) -> u32;
我会诚实地说,消费和归还self
感觉真的很奇怪,而且这也是不切实际的,如此处所示。
如果您遇到fn next(self) -> (Self, u32)
,但愿意改变StateHolder
的布局,请选择state: Option<State>
,因为Option
有take
:
let (new_state, byproduct) = self.state.take().unwrap().next();
self.state = Some(new_state);
byproduct
如果您在没有Option
的情况下被卡住,或者使用起来太痛苦,那么您确实可以使用std::mem::replace
,但是您需要一些State
来执行此操作。如果State
实现Default
,这很容易,但可能很昂贵:
let (new_state, byproduct) =
std::mem::replace(&mut self.state, State::default()).next();
std::mem::replace(&mut self.state, new_state);
byproduct
最后,您确实可以打破unsafe
以将值移出self.state
...但是如果计算在您填写之前发生恐慌,那么您已经打开了未定义行为的大门土地,那是baaad。