Rust:初始化库中的静态变量/引用?

Rust: initialize a static variable/reference in a lib?

提问人:JKL 提问时间:1/23/2022 最后编辑:JKL 更新时间:1/24/2022 访问量:2915

问:

我是 Rust 的新手。我正在尝试在库中创建一个静态变量,以便在编译库后对其进行初始化。然后,我将 lib 包含在主代码中,希望直接使用而无需再次调用。这是我尝试过的:DATAVec<u8>DATAinit_data()

my_lib.rs:

use lazy_static::lazy_static;

pub fn init_data() -> Vec<u8> {
    // some expensive calculations
}

lazy_static! {
    pub static ref DATA: Vec<u8> = init_data();  // supposed to call init_data() only once during compilation
}

main.rs:

use my_lib::DATA;
call1(&DATA);  // use DATA here without calling init_data()
call2(&DATA);

但事实证明,在.这段代码有什么问题?init_data()main.rs


更新:正如 Ivan C 指出的那样,在编译时不会运行。那么,“预加载”数据的正确选择是什么?lazy_static

lazy-initialization 静态初始化 惰性静态

评论

0赞 Ivan C 1/23/2022
惰性静态不会在编译时初始化,而是在首次访问时初始化。
0赞 JKL 1/23/2022
啊对。我会稍微改变我的问题。

答:

5赞 Kevin Reid 1/24/2022 #1

这里有两个问题:类型选择和执行分配。

在编译时无法构造 a、a 或任何其他需要堆分配的类型,因为此时堆分配器和堆尚不存在。相反,必须使用引用类型,该类型可以指向在二进制文件(而不是运行时堆中)中分配的数据,或者使用没有任何引用的数组(如果数据不是太大)。VecBox

接下来,我们需要一种方法来执行计算。从理论上讲,最干净的选择是持续评估——在编译时直接执行部分代码。

static DATA: &'static [u8] = {
    // code goes here
};

然而,在当前稳定的 Rust 版本(我写这篇文章时是 1.58.1)中,持续评估是非常有限的,因为你不能做任何看起来像 ping 值的事情,也不能使用任何属于特征的函数。它仍然可以做一些事情,主要是整数算术或构造其他“几乎是字面意思”的数据;例如:drop

const N: usize = 10;
static FIRST_N_FIBONACCI: &'static [u32; N] = &{
    let mut array = [0; N];
    array[1] = 1;
    let mut i = 2;
    while i < array.len() {
        array[i] = array[i - 1] + array[i - 2];
        i += 1;
    }
    array
};

fn main() {
    dbg!(FIRST_N_FIBONACCI);
}

如果无法使用 const 求值来表示计算,则需要以另一种方式执行:

  • 过程宏实际上是编译器插件,它们可以执行任意计算,但它们的输出是生成的 Rust 语法。因此,过程宏可以生成一个包含预计算数据的数组文本。

    过程宏的主要局限性是它们必须在专用的 crate 中定义(因此,如果您的项目是一个库 crate,那么现在它将是两个)。

  • 构建脚本是普通的 Rust 代码,可以编译或生成主编译使用的文件。它们不与编译器交互,但在编译开始之前由 Cargo 运行。

(与 const 评估不同,构建脚本和 proc 宏都不能使用正在构建的 crate 本身中定义的任何类型或常量;它们可以读取源代码,但它们运行得太早,无法在自己的代码中使用 crate 中的其他项目。

在你的情况下,因为你想预先计算一些数据,我认为最简单的方法是添加一个构建脚本,将数据写入文件,之后你的普通代码可以使用include_bytes从文件中嵌入这些数据![u8]

评论

0赞 JKL 1/24/2022
非常感谢,凯文·里德。这是非常有帮助的。是的,我也一直在怀疑我的数据类型。我倾向于使用构建脚本。
0赞 Chayim Friedman 1/24/2022
过程宏和生成脚本无法检查常量的值。