示例代码:
struct S1 {}
struct S2 {}
struct S3 {}
enum State {
Zero,
One(S1),
Two(S1, S2),
Three(S1, S2, S3),
}
struct Client {
state: Option<State>,
}
impl Client {
fn try_advancing(&mut self) {
/* other code */
if let Some(inner) = std::mem::replace(&mut self.state, None) {
match inner {
State::Zero => {
if predicate0() {
self.state = Some(State::One(S1 {}));
}
else {
// code won't compile as we
// no longer own inner after partial move
self.state = Some(inner);
}
},
State::One(s1) => {
if predicate1() {
self.state = Some(State::Two(s1, S2 {}));
}
else {
self.state = Some(inner);
}
},
State::Two(s1, s2) => {
if predicate2() {
self.state = Some(State::Three(s1, s2, S3 {}));
}
else {
self.state = Some(inner);
}
},
State::Three(..) => {
if predicate3() {
// something else happens now
}
}
}
}
}
}
我需要查看state
来确定是否移动到下一个转换,但如果我借用它,那么我无法转换,因为我不拥有该值。
作为可能的解决方案,我可以使用
智能指针
第二个匹配语句(第一个借用并确定是否需要转换,第二个移动并进行转换)
按原样“重建”枚举,即
self.state = Some(inner);
变为self.state = State::Zero;
只借用内部的内容,直到我知道我想转移所有权,然后执行 if let,例如
State::One(ref s1) => {
if predicate1() {
if let State::One(s1) = inner {
self.state = Some(State::Two(s1, S2 {}));
- 导出单元结构的
复制
和克隆
。
所有这些解决方案都会产生运行时成本以及我认为不优雅的代码。如果这是另一种语言,我可以按照我认为应该的方式编写算法,但对于 Rust,生命周期似乎阻止我这样做。如果有一种方法可以告诉 Rust 编译器“在 if 语句的这个分支中,我想撤销我的部分移动并将 inner
移回到原来的位置。”或者也许,“是的,我借用了数据,但现在我不再需要这些引用并想要移动数据。”有这样的办法吗?或者我还没有考虑过任何更好的选择?
最佳答案
您可以将 if
移动到匹配臂中,这样您就可以获得不同的绑定(bind):
match inner {
State::Zero if predicate0() => {
self.state = Some(State::One(S1 {}));
},
State::Zero => {
self.state = Some(inner);
},
State::One(s1) if predicate1() => {
self.state = Some(State::Two(s1, S2 {}));
},
State::One(_) => {
self.state = Some(inner);
},
State::Two(s1, s2) if predicate2() => {
self.state = Some(State::Three(s1, s2, S3 {}));
},
State::Two(_, _) => {
self.state = Some(inner);
},
// ... snip ...
}
关于rust - 生命周期阻碍了状态机返回到最近的状态,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68553959/