我正在尝试替换可变借用中的值;将它的一部分移动到新值中:
enum Foo<T> {
Bar(T),
Baz(T),
}
impl<T> Foo<T> {
fn switch(&mut self) {
*self = match self {
&mut Foo::Bar(val) => Foo::Baz(val),
&mut Foo::Baz(val) => Foo::Bar(val),
}
}
}
上面的代码不起作用,这是可以理解的,将值移出 self
会破坏它的完整性。但由于该值随后立即被删除,我(如果不是编译器)可以保证它的安全。
有什么办法可以实现吗?我觉得这是针对不安全代码的工作,但我不确定它会如何工作。
最佳答案
mem:uninitialized
自 Rust 1.39 以来已被弃用,取而代之的是 MaybeUninit
.
然而,这里不需要未初始化的数据。相反,您可以使用 ptr::read
获取 self
引用的数据。
此时,tmp
拥有枚举中数据的所有权,但如果我们要删除 self
,该数据将尝试由析构函数读取,导致内存不安全。
然后我们执行转换并将值放回原处,恢复类型的安全性。
use std::ptr;
enum Foo<T> {
Bar(T),
Baz(T),
}
impl<T> Foo<T> {
fn switch(&mut self) {
// I copied this code from Stack Overflow without reading
// the surrounding text that explains why this is safe.
unsafe {
let tmp = ptr::read(self);
// Must not panic before we get to `ptr::write`
let new = match tmp {
Foo::Bar(val) => Foo::Baz(val),
Foo::Baz(val) => Foo::Bar(val),
};
ptr::write(self, new);
}
}
}
此代码的更高级版本将防止 panic 从这段代码中冒出,而是导致程序中止。
另见:
关于rust - 暂时搬出借用的内容,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29570781/