rust - 在编译时使用 serde_json 反序列化文件

标签 rust deserialization json-deserialization serde

在我的程序开始时,我从一个文件中读取数据:

let file = std::fs::File::open("data/games.json").unwrap();
let data: Games = serde_json::from_reader(file).unwrap();

我想知道在编译时如何做到这一点,原因如下:

  1. 性能:无需在运行时反序列化
  2. 可移植性:该程序可以在任何机器上运行,不需要包含数据的 json 文件。

我可能还需要提一下,数据可以是只读的,这意味着解决方案可以将其存储为静态数据。

最佳答案

这很简单,但会导致一些潜在的问题。首先,我们需要处理一些事情:我们是想从文件加载对象树,还是在运行时解析它?

99% 的时间,在启动时解析为 static ref 对人们来说已经足够了,所以我将为您提供该解决方案;我会在最后向您指出“其他”版本,但这需要很多更多的工作并且是特定于域的。

您正在寻找能够在编译时包含文件的宏(因为它必须是宏)在标准库中:std::include_str! .顾名思义,它会在编译时获取您的文件,并从中生成一个 &'static str 供您使用。然后您可以自由地使用它做任何您喜欢的事情(例如解析它)。

从那里开始,使用 lazy_static! 就很简单了为我们的 JSON Value(或您决定使用的任何内容)生成一个 static ref 供程序的每个部分使用。例如,在您的情况下,它可能看起来像这样:

const GAME_JSON: &str = include_str!("my/file.json");

#[derive(Serialize, Deserialize, Debug)]
struct Game {
    name: String,
}

lazy_static! {
    static ref GAMES: Vec<Game> = serde_json::from_str(&GAME_JSON).unwrap();
}

执行此操作时需要注意两件事:

  1. 这将大量 使您的文件大小膨胀,因为&str 没有以任何方式压缩。考虑 gzip
  2. 您需要担心对同一 static ref 的多个线程访问的常见问题,但由于它不是可变的,您实际上只需要担心它的一部分

另一种方法需要在编译时使用过程宏动态生成对象。如前所述,除非您真的在解析该 JSON 时有真的昂贵的启动成本,否则我不会推荐它;大多数人不会,我上次遇到这种情况是在处理深度嵌套的多 GB JSON 文件时。

您要注意的 crate 是用于代码生成的 proc_macro2syn;其余部分与您编写普通方法的方式非常相似。

关于rust - 在编译时使用 serde_json 反序列化文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58359340/

相关文章:

rust - 为什么RefCell不能作为self参数

regex - 在 Rust 中保存/加载编译的正则表达式?

c# - 使用 Newtonsoft Json.NET 解析具有名称值对的多维 JSON 数组

android - 在一个对象中同时使用 jackson 和 ormlite 注释时出现异常

rust - 我应该如何在 rust 中为 jsonwebtokens 强制执行反序列化类型?

json - 无法使用 Rustc-serialize 处理 JSON 中的可选字段

swift - 导致 JSON 解码在 Swift 4 中失败的可选 URL

Rust:在 LLVM Bitcode 中包含依赖项

rust - 我应该按值还是按引用传递函数对象?

rust - 创建具有无限参数的宏