如何解决如何在不获取 E0507 的情况下将包含 Vec 的结构移入/移出静态数组?
我需要一个静态结构数组,并且这些结构包含一个 Vec。我可以管理实际值的生命周期。我收到以下错误:
: Mar23 ; cargo test
Compiling smalltalk v0.1.0 (/Users/dmason/git/AST-Smalltalk/rust)
error[E0507]: cannot move out of `dispatchTable[_]` as `dispatchTable` is a static item
--> src/minimal.rs:32:44
|
30 | let old = ManuallyDrop::into_inner(dispatchTable[pos]);
| ^^^^^^^^^^^^^^^^^^ move occurs because `dispatchTable[_]` has type `ManuallyDrop<Option<Box<dispatch>>>`,which does not implement the `copy` trait
error: aborting due to prevIoUs error
这是一个最小的可编译示例:
#[derive(copy,Clone)]
struct MethodMatch {
hash: i64,method: Option<bool>,}
#[derive(Clone)]
pub struct dispatch {
class: i64,table: Vec<MethodMatch>,}
const max_classes : usize = 100;
use std::mem::ManuallyDrop;
const no_dispatch : ManuallyDrop<Option<Box<dispatch>>> = ManuallyDrop::new(None);
static mut dispatchTable : [ManuallyDrop<Option<Box<dispatch>>>;max_classes] = [no_dispatch;max_classes];
use std::sync::RwLock;
lazy_static! {
static ref dispatchFree : RwLock<usize> = {RwLock::new(0)};
}
pub fn addClass(c : i64,n : usize) {
let mut index = dispatchFree.write().unwrap();
let pos = *index;
*index += 1;
replacedispatch(pos,c,n);
}
pub fn replacedispatch(pos : usize,c : i64,n : usize) -> Option<Box<dispatch>> {
let mut table = Vec::with_capacity(n);
table.resize(n,MethodMatch{hash:0,method:None});
unsafe {
let old = ManuallyDrop::into_inner(dispatchTable[pos]);
dispatchTable[pos]=ManuallyDrop::new(Some(Box::new(dispatch{class:c,table:table})));
old
}
}
我的想法是让 replacedispatch
创建一个新的 dispatch 选项对象,并将数组中的当前值替换为新值,返回原始值,并且调用者将获得 dispatch 选项值并能够使用然后删除/释放对象。
我发现如果我在确定的错误点之后添加 .clone()
它将编译。 但是然后原始值永远不会被丢弃,因此(into_inner 是多余的并且)我正在造成内存泄漏!。我是否必须手动删除它(如果我能弄清楚如何)?我以为这就是 ManuallyDrop
给我买的。从理论上讲,如果我将 Vec 中的字段副本创建为副本,则该副本将指向旧数据,因此当该对象被删除时,内存将被释放。但是(a)这看起来很脏,(b)它有点丑陋,不必要的代码(我必须处理 Some/None 情况,查看 Vec 内部等),并且(c)我看不出如何我什至会这样做!!!!
解决方法
正如编译器告诉您的那样,您不能将值移出其他人可观察到的位置。但是,由于您已准备好替代品,您可以使用 std::mem::replace
:
pub fn replaceDispatch(pos: usize,c: i64,n: usize) -> Option<Box<Dispatch>> {
... table handling omitted ...
unsafe {
let old = std::mem::replace(
&mut dispatchTable[pos],ManuallyDrop::new(Some(Box::new(Dispatch {
class: c,table: table,}))),);
ManuallyDrop::into_inner(old)
}
}
事实上,由于您使用 Option
来管理 Dispatch
的生命周期,因此您根本不需要 ManuallyDrop
,您也不需要 { {1}}:playground。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。