rust 如果我不想运行析构函数,我如何从一个有析构函数的结构体中移出?

9wbgstp7  于 2023-02-23  发布在  其他
关注(0)|答案(1)|浏览(150)

假设我有一个Rust struct,它有一个析构函数:

pub struct D1 {
    a: String,
    b: String
}

impl Drop for D1 {
    fn drop(&mut self) {
        println!("{0}", self.a)
    }
}

我想实现一个方法,将部分或全部字段移出对象,并在进程中销毁它。显然,如果对象的析构函数运行,这是不安全的--它将尝试不安全地读取被移动的字段。然而,如果析构函数被抑制,这应该是安全的。但我找不到一种方法来抑制析构函数,使移动安全。
mem::forget不起作用,因为编译器在处理析构函数时没有特别处理它:

impl D1 {
    fn into_raw_parts(self) -> (String, String) {
        let (a, b) = (self.a, self.b); // cannot move here
        mem::forget(self);
        (a, b)
    }
}

ManuallyDrop也不起作用-它只通过引用提供内部数据,防止移动:
一个二个一个一个
我大概可以通过研究unsafe代码来解决这个问题,但我想知道是否有一种安全的方法来做到这一点--我是否错过了一些API或其他技术来告诉Rust我可以安全地移出一个值,因为我不打算运行析构函数?

izj3ouym

izj3ouym1#

在安全代码中,无法使实现Drop的类型保持未初始化状态,但是,可以使用伪值使其保持初始化状态:

use std::mem;

impl D1 {
    fn into_raw_parts(self) -> (String, String) {
        (mem::take(&mut self.a), mem::take(&mut self.b))
    }
}

这将给self留下空字符串(甚至不分配任何内存)。当然,Drop实现必须容忍这种情况,并且不做不希望的事情。
如果真实的情况中的字段类型没有方便的占位符值,那么可以将字段设置为Option s。当Drop::drop()本身需要移出self时,这也是一种常用的技术。

相关问题