微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

如何在不获取 E0507 的情况下将包含 Vec 的结构移入/移出静态数组?

如何解决如何在不获取 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)
    }
}

Playground

事实上,由于您使用 Option 来管理 Dispatch 的生命周期,因此您根本不需要 ManuallyDrop,您也不需要 { {1}}:playground

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。