如何在不获取 E0507 的情况下将包含 Vec to/from 的结构移动到静态数组?
How can I move structs containing Vec to/from a static array without getting E0507?
我需要一个静态结构数组,该结构包含一个 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 选项对象,并用新值替换数组中的当前值,返回原始值,调用者将获得调度选项值并能够使用然后 drop/deallocate 对象。
我发现如果我在识别出的错误点之后添加 .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
,您也不需要Box
: playground.
我需要一个静态结构数组,该结构包含一个 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 选项对象,并用新值替换数组中的当前值,返回原始值,调用者将获得调度选项值并能够使用然后 drop/deallocate 对象。
我发现如果我在识别出的错误点之后添加 .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
,您也不需要Box
: playground.