如何使Rust单例的析构函数运行?

ust*_*ion 2 singleton raii rust

这些是我所知道的在Rust中创建单例的方法:

#[macro_use]
extern crate lazy_static;

use std::sync::{Mutex, Once, ONCE_INIT};

#[derive(Debug)]
struct A(usize);
impl Drop for A {
    fn drop(&mut self) {
        // This is never executed automatically.
        println!(
            "Dropping {:?} - Important stuff such as release file-handles etc.",
            *self
        );
    }
}

// ------------------ METHOD 0 -------------------
static PLAIN_OBJ: A = A(0);

// ------------------ METHOD 1 -------------------
lazy_static! {
    static ref OBJ: Mutex<A> = Mutex::new(A(1));
}

// ------------------ METHOD 2 -------------------
fn get() -> &'static Mutex<A> {
    static mut OBJ: *const Mutex<A> = 0 as *const Mutex<A>;
    static ONCE: Once = ONCE_INIT;
    ONCE.call_once(|| unsafe {
        OBJ = Box::into_raw(Box::new(Mutex::new(A(2))));
    });
    unsafe { &*OBJ }
}

fn main() {
    println!("Obj = {:?}", PLAIN_OBJ); // A(0)
    println!("Obj = {:?}", *OBJ.lock().unwrap()); // A(1)
    println!("Obj = {:?}", *get().lock().unwrap()); // A(2)
}
Run Code Online (Sandbox Code Playgroud)

这些都不会在程序退出时调用A析构函数(drop()).这是方法2(堆分配)的预期行为,但我没有查看实现,lazy_static!知道它将是类似的.

这里没有RAII.我可以在C++中实现RAII单例的行为(我以前用C++编写代码直到一年后,所以我的大多数比较都与它有关 - 我不知道很多其他语言)使用函数局部静态:

A& get() {
  static A obj; // thread-safe creation with C++11 guarantees
  return obj;
}
Run Code Online (Sandbox Code Playgroud)

这可能是在实现定义区域中分配/创建(延迟),并且在程序的生命周期内有效.当程序终止时,析构函数将被确定性地运行.我们需要避免从其他静态的析构函数中访问它,但我从未遇到过这种情况.

我可能需要释放资源,我想要drop()运行.现在,我最终在程序终止之前手动完成它(在所有线程加入之后朝向main的末尾).

我甚至不知道如何lazy_static!使用它,所以我避免使用它,只去了方法2,我可以在最后手动销毁它.

我不想这样做; 有没有办法让我在Rust中有这样一个RAII表现单身?

Mat*_* M. 7

特别是单身人士和一般的全局构造函数/析构函数是一种祸害(特别是在C++等语言中).

我会说它们引起的主要(功能)问题分别被称为静态初始化(resp.破坏)命令惨败.也就是说,很容易在这些全局变量之间意外地创建依赖循环,即使没有这样的循环,编译器也不会立即清楚它们应该构建/销毁它们的顺序.

它们还可能导致其他问题:启动速度较慢,意外共享内存,......

在鲁斯特,采取的态度是在主要之前/之后没有生命.因此,尝试获取C++行为可能无法按预期工作.

如果您:将获得更多语言支持:

  • 放弃全球方面
  • 放弃尝试拥有单个实例

(作为奖励,并行测试也会更容易)

因此,我的建议是简单地坚持使用局部变量.实例化它main,通过调用堆栈中的值/引用传递它,不仅避免了那些棘手的初始化顺序问题,而且还会破坏.

  • 我们需要一个机器人自动回复每个问题,单词"singleton","你真的不想那样做". (3认同)
  • 它有它的位置 - 这是 Rust 本身的一个简单示例:假设您需要单个对象在所有测试中持久存在(在“货物测试”期间作为单独的线程并行运行)。也许它正在模拟一个网络,在一堆转换后写入单个文件,具体取决于全局参数,这些参数随着测试的运行而变化,这对于其他测试看到变化很重要。模式太抽象了,不能简单地丢弃,即使有些模式很少使用,它们仍然有一席之地。但你确实回答了我的问题,这是不可能的 - 所以如果我没有得到其他人,我会接受这个 - 谢谢 (2认同)