有没有办法在 Rust 库中包含二进制或文本文件?
Posted
技术标签:
【中文标题】有没有办法在 Rust 库中包含二进制或文本文件?【英文标题】:Is there any way to include binary or text files in a Rust library? 【发布时间】:2015-12-21 07:44:50 【问题描述】:我正在尝试创建一个库,并且我想在其中包含一些二进制(或文本)文件,这些文件将包含将在运行时解析的数据。
我的目的是控制这些文件,不断更新它们,并在每次更新时更改库的版本。
这可以通过货物实现吗?如果是这样,我如何从我的库中访问这些文件?
我想到的一种解决方法是包含一些带有结构和/或常量的.rs
文件,例如&str
,它将存储数据,但我觉得它有点难看。
编辑:
我已将接受的答案更改为更适合我情况的答案,但请查看Shepmaster's answer,因为这可能更适合您的情况。
【问题讨论】:
将在运行时解析 => 为什么?由于数据是静态的,将已经解析的数据存储在二进制文件中比在运行时解析它更有效。 Rust 在编译时可以表示的内容相当有限(很不幸),但是您提到维护一个.rs
文件,因此在您的情况下似乎是可能的。如果是这种情况,那么我建议使用 build.rs
文件,这是 Rust 中的“构建脚本”,它允许您在构建“正确”之前解析源文件并生成 .rs
文件。
更准确地说,这些数据已经被解析并且需要移动到结构体中,比如HashMap
,它不能被初始化(至少不使用lazy_static
crate)。这就是为什么我需要在运行时“解析”它们。当我想更新数据时,将它们放在二进制(或文本)文件中可以更容易地只替换这个文件。然而,结合使用build.rs
和lazy_static
crate 听起来像是一个更好的选择,我会试一试。感谢您的建议!
【参考方案1】:
免责声明:我在评论中提到过,但让我在这里重申一下,因为它给了我更多阐述的空间。
正如 Shepmaster 所说,可以使用 include_bytes!
和 include_str!
宏在 Rust 库/可执行文件中包含文本或二进制逐字记录。
但是,在你的情况下,我会避免它。通过将内容的解析推迟到运行时:
您允许构建有缺陷的工件。 您会产生(更多)运行时开销(解析时间)。 您会产生(更多)空间开销(解析代码)。Rust 承认了这个问题,并提供了多种代码生成机制来克服这些限制:
宏:如果逻辑可以编码成宏,那么可以直接包含在源文件中 插件:已启动的宏,可以对任意逻辑进行编码并生成精细代码(参见regex!
)
build.rs
:在编译之前运行的独立“Rust 脚本”,其作用是生成 .rs
文件
在您的情况下,build.rs
脚本听起来很合适:
你的解析结果可以用不同的方式编码,从函数到静态(可能是lazy_static!
),因为build.rs
可以生成任何有效的Rust代码。
您可以在the Cargo Documentation中看到如何使用build.rs
;您将在那里找到如何将其与 Cargo 集成以及如何创建文件(等等)。
【讨论】:
【参考方案2】:include_bytes!
宏似乎与您想要的很接近。它只给你一个字节数组的引用,所以你必须从那个开始做任何解析:
static HOST_FILE: &'static [u8] = include_bytes!("/etc/hosts");
fn main()
let host_str = std::str::from_utf8(HOST_FILE).unwrap();
println!("Hosts are:\n", &host_str[..42]);
如果你有 UTF-8 内容,你可以使用include_str!
,正如Benjamin Lindley所指出的那样:
static HOST_FILE: &'static str = include_str!("/etc/hosts");
fn main()
println!("Hosts are:\n", &HOST_FILE[..42]);
【讨论】:
如果你想要文本(而不是二进制数据),并且它已经是utf8格式,你不能只使用include_str!
,而不是使用include_bytes!
然后转换它吗? 即 -- let host_str = include_str!("/etc/hosts");
@BenjaminLindley 嗯,好点子!我看到include!
并意识到它不对但直接跳过include_str!
。以上是关于有没有办法在 Rust 库中包含二进制或文本文件?的主要内容,如果未能解决你的问题,请参考以下文章