rust - 使用不能声明为静态的函数在运行时初始化可变静态变量

标签 rust ffi lifetime

这个问题在这里已经有了答案:





How do I create a global, mutable singleton?

(3 个回答)



How can you make a safe static singleton in Rust?

(3 个回答)



Recommended way to wrap C lib initialization/destruction routine

(2 个回答)


2年前关闭。




use std::sync::Once;

struct Store;

impl Store {
    fn new() -> Store {
        Store {
            manifest: RwLock::new(/* ... */), // @note: RwLock does not implement Clone
        }
    }

    fn save(&mut self) {
        // ...
    }
}


失败代码:

static mut store: Option<Store> = None;
static INIT: Once = Once::new();

unsafe {
    INIT.call_once(|| {
        store = Some(Store::new());
    });
    store.unwrap().save(); // Error: cannot move out of static item `store`
}

错误很简单,但这是我迫切需要完成的事情,因为 Store::new()在后台进行了大量计算成本高昂的工作。

我要求看似不可能的事情:声明类型为 Store 的静态变量并在运行时初始化它——假设 new不能是 static由于该函数内发生的绝对关键的内部可变性。此外,RwLock是必需的,不能被克隆。我什至敢问这是否可以以线程安全的方式完成?

没有推迟 new函数调用或其内部属性作为我的程序中的后续函数调用(否则不相关)依赖于它。

为了帮助使问题更清楚,这是在 FFI 的范围内。我对程序的生命周期或以更安全的方式管理此变量的能力没有太多控制权。虽然,我绝对想要这个 Store变量在程序的生命周期内存活!

我的问题是概念性的。我不希望这个确切的代码被稍微修改并突然编译。我在这里问一个问题,因为我无法理解如何实现我想要的。我尝试了其他几种方法……这是迄今为止我所做的最好的尝试。

最佳答案

如果没有 MCVE,很难确定你想要什么,但这是我设法做到的。

首先,正如编译器所说,您的问题非常简单:unwrap消耗选项,你不能消耗静态。但是,您似乎真正想要的是就地改变商店,这是可能的,AFAIK 甚至以多种方式。

我选择的是跟随。一般来说,要就地改变某些东西,我们必须获得对它的独占引用。根据 Option 的文档,有 as_mut method , 它转换 &mut Option<T>进入 Option<&mut T> .重要的部分是这个新选项是拥有的,即它不存储在静态中(而是引用静态),因此它可以被 unwrap 使用, 产生必要的 &mut引用,我们可以在上面调用save :

fn main() {
    unsafe {
        INIT.call_once(|| {
            store = Some(Store::new());
        });
        store.as_mut().unwrap().save();
    }
}

Playground可能实现您的目标。

但是,我不太确定您是否使用了 static mut是有道理的。首先,完全不清楚为什么需要使用 &mut selfsave : 如果你只有 StoreRwLock ,您可以使用共享引用,因为这就是锁定的重点。在这种情况下,您可以简单地存储 Store (双关语无意)在 lazy_static :
// skipping definitions

use lazy_static::lazy_static;

lazy_static! {
    static ref store: Store = Store::new();
}

fn main() {
    store.save();
}

Playground

关于rust - 使用不能声明为静态的函数在运行时初始化可变静态变量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60409156/

相关文章:

memory - 为什么Rust中的打印内存地址同时包含40位和48位地址?

haskell - 使用 FFI 的可执行文件是否需要 GHC 选项?

ocaml - 使用它编译C lib和OCaml exe,全部使用ocamlfind

rust - 为什么不能将引用的生存期推论为所有上下文可能性中最短的?

Rust:我可以通过以简单的方式在较小的范围内借用整个固定大小的数组来获得固定大小的切片吗

rust - 特征对象引用的生命周期

rust - 支持 String 和 &str 的 Hashmap

rust - 如何消除Rust的特征?

rust - Rust 中的 "default host triple"是什么?

rust - 我如何使用 cbindgen 返回并释放一个 Box<Vec<_>>?