提问人:JKL 提问时间:1/23/2022 最后编辑:JKL 更新时间:1/24/2022 访问量:2915
Rust:初始化库中的静态变量/引用?
Rust: initialize a static variable/reference in a lib?
问:
我是 Rust 的新手。我正在尝试在库中创建一个静态变量,以便在编译库后对其进行初始化。然后,我将 lib 包含在主代码中,希望直接使用而无需再次调用。这是我尝试过的:DATA
Vec<u8>
DATA
init_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
答:
这里有两个问题:类型选择和执行分配。
在编译时无法构造 a、a 或任何其他需要堆分配的类型,因为此时堆分配器和堆尚不存在。相反,必须使用引用类型,该类型可以指向在二进制文件(而不是运行时堆中)中分配的数据,或者使用没有任何引用的数组(如果数据不是太大)。Vec
Box
接下来,我们需要一种方法来执行计算。从理论上讲,最干净的选择是持续评估——在编译时直接执行部分代码。
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]
评论