如何在Rust库中运行清理代码?

时间:2018-02-11 14:10:00

标签: static rust destroy

我正在制作一个跨平台终端库。因为我的库改变了终端的状态,所以我需要恢复进程结束时对终端所做的所有更改。我现在正在实现此功能,并思考如何在最后恢复到原始终端状态的方法。

我认为静态变量在程序启动时被初始化,而当程序结束时,这个静态变量将被销毁。由于我的静态变量是一个已实现Drop特性的结构,因此它会在程序结束时被删除,但事实并非如此,因为字符串" drop称为"从未打印过:

static mut SOME_STATIC_VARIABLE: SomeStruct = SomeStruct { some_value: None };

struct SomeStruct {
    pub some_value: Option<i32>,
}

impl Drop for SomeStruct {
    fn drop(&mut self) {
        println!("drop called");
    }
}

为什么程序结束时不调用drop()?我的想法是错的,我应该采取另一种方式吗?

2 个答案:

答案 0 :(得分:5)

Rust的一个原则是no life before main,这意味着在主之后没有生命。

在main之前或之后正确排序构造函数和析构函数存在相当大的挑战。在C ++中,情况被称为static initialization order fiasco,虽然它有解决方法,但它的挂件(静态销毁订单惨败)却没有。

在Rust中,'static生命周期加剧了挑战:在静态中运行析构函数可能会导致观察部分破坏的其他静态。这是不安全的。

为了安全地破坏静力学,语言需要引入'static生命周期的子集来命令构造/破坏静力学,同时使这些生命周期仍为'static来自main }} ...

如何在程序的开头/结尾运行代码?

只需在main的开头/结尾处运行代码即可。请注意,在main开头构建的任何结构都将以与构造相反的顺序在其末尾删除。

如果我不是自己写main

很好地询问main的作者。

答案 1 :(得分:5)

在库中强制执行初始化和清理代码的一种方法是引入Context类型,该类型只能使用公共new()函数构建,并实现Drop特征。库中需要初始化的每个函数都可以使用Context作为参数,因此用户需要在调用这些函数之前创建一个函数。任何清理代码都可以包含在Context::drop()

pub struct Context {
    // private field to enforce use of Context::new()
    some_value: Option<i32>,
}

impl Context {
    pub fn new() -> Context {
        // Add initialization code here.
        Context { some_value: Some(42) }
    }
}

impl Drop for Context {
    fn drop(&mut self) {
        // Add cleanup code here
        println!("Context dropped");
    }
}

// The type system will statically enforce that the initialization
// code in Context::new() is called before this function, and the
// cleanup code in drop() when the context goes out of scope.
pub fn some_function(_ctx: &Context, some_arg: i32) {
    println!("some_function called with argument {}", some_arg);
}