rust - 生命周期阻碍了状态机返回到最近的状态

标签 rust

示例代码:

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来确定是否移动到下一个转换,但如果我借用它,那么我无法转换,因为我不拥有该值。

作为可能的解决方案,我可以使用

  1. 智能指针

  2. 第二个匹配语句(第一个借用并确定是否需要转换,第二个移动并进行转换)

  3. 按原样“重建”枚举,即 self.state = Some(inner); 变为 self.state = State::Zero;

  4. 只借用内部的内容,直到我知道我想转移所有权,然后执行 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/

    相关文章:

    rust - 预期为 std::iter::Iterator,但找到了 std::iter::Iterator

    rust - 生成 rustdoc 时如何使用本地文件作为 crate Logo ?

    string - 如何在 String、&str、Vec<u8> 和 &[u8] 之间进行转换?

    rust - Amethyst 的 Loader 找不到 Assets 文件

    rust - 为什么从 Actix Web 处理程序中的 Rusoto S3 流读取会导致死锁?

    enums - 如何在 Rust 中指定枚举的表示类型以与 C++ 接口(interface)?

    rust - 是否可以禁用 Cargo 中的单个默认功能?

    generics - 具有特征的通用函数,用于读取提示错误特征的数字

    rust - Vanilla Rust中的目录遍历

    string - 如何强制 Rust 中的字符串不能为空?