如何在不冒犯借用检查器的情况下进行计算状态转换?
How can I do computed state transitions without offending the borrow checker?
我已经编写了这段代码用于在状态之间转换,但是如果未能通过借用检查器:
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 中编写它,而无需进行不必要的复制?
最简单的方法:
fn next(&mut self) -> u32;
老实说,消费和 return 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
中移出...但是,如果计算在您重新填充之前出现恐慌,那么您已经打开了大门未定义的行为土地,那是糟糕的。
我已经编写了这段代码用于在状态之间转换,但是如果未能通过借用检查器:
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 中编写它,而无需进行不必要的复制?
最简单的方法:
fn next(&mut self) -> u32;
老实说,消费和 return 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
中移出...但是,如果计算在您重新填充之前出现恐慌,那么您已经打开了大门未定义的行为土地,那是糟糕的。