在Rust中,如何释放全局静态的OnceCell的内部对象?

编程语言 2026-07-09

我有以下代码

use tokio::sync::OnceCell;

struct MyStruct {}

impl MyStruct {
    pub fn new() -> anyhow::Result<Self> {
        Ok(Self {})
    }
}

impl Drop for MyStruct {
    fn drop(&mut self) {
        println!("---> auto drop .")
    }
}

static HOLDER: OnceCell<MyStruct> = OnceCell::const_new();

async fn g2() -> &'static MyStruct {
    HOLDER
        .get_or_init(|| async { MyStruct::new().unwrap() })
        .await
}

#[tokio::main]
async fn main() {
    println!("Hello, world!");

    // _ms will auto drop
    let _ms = MyStruct {};

    // the inner object, instance of `MyStruct` will not drop
    let _ins = g2().await;
}

Cargo.toml

[dependencies]
anyhow = "1.0.102"
tokio = {version = "1.52.0", features = ["full"]}

正如注释所说,_ms 将会自动被丢弃,但 _ins 不会被丢弃。

我的问题是如何丢弃由 HOLDER 创建的 MyStruct 实例。

解决方案

原因是 HOLDER 是一个静态变量,静态变量是全局的,存在永远并且会 参见文档:

[items.static.lifetime] 静态项具有静态生命周期,超出Rust程序中的所有其他生命周期。静态项在程序结束时不会调用drop。

你在这里实现的范式被称为单例模式,其中 g2() 是单例访问器。Rust的单例在程序结束时不会被丢弃,它们只是不再存在。


我的问题是如何丢弃由HOLDER创建的MyStruct实例。

不要把它设为全局静态变量。把它声明在 main 中,并作为参数传递。避免全局静态变量有很多原因,这只是其中一个。

如果你只是想要以C 风格的编程,拥有一组函数及它们所操作的全局变量,那么将所有变量放到一个结构体中,并把函数移入该结构体 impl,并带一个 &self/&mut self 参数。然后在 main 函数中初始化该结构体,并调用该结构体的入口函数或类似的函数。这几乎会得到与仅使用全局函数相同的布局,但有一个好处:它们现在绑定到一个将被可靠丢弃的结构体上。

站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章