rust 移出枚举中的可变自引用(在自引用之前)

k4emjkb1  于 12个月前  发布在  其他
关注(0)|答案(1)|浏览(105)

我有一个类似有限状态机的枚举,它有不同的状态,包含不同类型的缓冲区。
在我的“transition”方法中,我更新了一个枚举字段,并有条件地将self替换为不同的变量,重用旧的字段值。
但是在一个特定的情况下,我想将一个大的缓冲区从旧的变体移动到新的变体,借用检查不会让我。
什么是正确的方法来做到这一点,同时避免昂贵的复制整个缓冲区?

impl EnumBased {
    fn step(&mut self) {
        match self {
            EnumBased::A(..) => { /* do something */ },
            EnumBased::B {
                buffer,  // &mut Buffer
            } => { 
                buffer.do_something()
                if something {
                    // consume buffer, moving out of self
                    let inner = buffer.to_inner();  // <-- at this point, can't move out of a mutable reference
                    // overwrite now-defunct self
                    *self = EnumBased::C { inner, ... }
                }
            },
        }
    }
}

字符串

0s0u357o

0s0u357o1#

首先,我将您的代码更改为几乎可以编译的代码。

pub enum EnumBased {
    B { buffer: Vec<u8> },
    C { buffer: Vec<u8> },
}

impl EnumBased {
    pub fn step(&mut self) {
        *self = match self {
            Self::B { buffer } => {
                buffer.pop();
                Self::C { buffer } // expected `Vec<u8>`, found `&mut Vec<u8>`
            }
            _ => todo!(),
        };
    }
}

字符串
如果一个缓冲区可以很便宜地构建(比如Vec),你可以简单地用一个空的缓冲区来替换它,一种方法是用std::mem::take

*self = match self {
    Self::B { buffer } => {
        buffer.pop();

        let buffer = std::mem::take(buffer);
        Self::C { buffer }
    }
    _ => todo!(),
};


如果这不可能,你可以让你的enum廉价地构造。要么使用现有的廉价变体,要么为此专门创建一个新的变体。然后你可以使用std::mem::replace来简单地替换self

pub enum EnumBased {
    B { buffer: Vec<u8> },
    C { buffer: Vec<u8> },
    Invalid
}

impl EnumBased {
    pub fn step(&mut self) {
        *self = match std::mem::replace(self, Self::Invalid) {
            Self::B { mut buffer } => {
                buffer.pop();
                Self::C { buffer }
            }
            _ => todo!(),
        };
    }
}


使用专用变量的好处是,如果你在这个函数之外看到它,你就知道出了问题。

相关问题