2个稳定版本

1.0.61 2021年1月19日
1.0.44 2020年1月8日

424编码 中排名

Download history 31/week @ 2024-03-11 23/week @ 2024-03-18 22/week @ 2024-03-25 38/week @ 2024-04-01 15/week @ 2024-04-08 23/week @ 2024-04-15 25/week @ 2024-04-22 24/week @ 2024-04-29 20/week @ 2024-05-06 22/week @ 2024-05-13 29/week @ 2024-05-20 14/week @ 2024-05-27 20/week @ 2024-06-03 17/week @ 2024-06-10 19/week @ 2024-06-17 21/week @ 2024-06-24

79 每月下载次数
alt_cargo_metadata 中使用

MIT/Apache

530KB
12K SLoC

Serde JSON 构建状态 最新版本 Rustc 版本 1.31+

Serde是一个框架,用于高效和泛型地将Rust数据结构进行序列化和反序列化。


[dependencies]
serde_json = "1.0"

你可能正在寻找

JSON是一种广泛使用的开放标准格式,使用人类可读的文本来传输由键值对组成的数据对象。

{
    "name": "John Doe",
    "age": 43,
    "address": {
        "street": "10 Downing Street",
        "city": "London"
    },
    "phones": [
        "+44 1234567",
        "+44 2345678"
    ]
}

在Rust中处理JSON数据时,你可能会遇到以下三种常见方式。

  • 作为文本数据。未处理的JSON数据字符串,您可能在HTTP端点接收到,从文件中读取或准备发送到远程服务器。
  • 作为无类型或松散类型表示。您可能想在将JSON数据传递之前检查其有效性,但不知道它包含的结构。或者您想进行非常基本的操作,如在一个特定的位置插入一个键。
  • 作为强类型的Rust数据结构。当您期望所有或大部分数据都符合特定结构,并且想在不受JSON松散特性的干扰下完成实际工作时。

Serde JSON 提供了一种高效、灵活、安全的方法来在以下各种表示形式之间转换数据。

在未类型化的 JSON 值上操作

任何有效的 JSON 数据都可以以下递归枚举表示进行操作。这种数据结构是 serde_json::Value

enum Value {
    Null,
    Bool(bool),
    Number(Number),
    String(String),
    Array(Vec<Value>),
    Object(Map<String, Value>),
}

可以使用 serde_json::from_str 函数将 JSON 数据字符串解析为 serde_json::Value。还有 from_slice 用于从字节数组解析,以及 from_reader 用于从文件或 TCP 流等任何 io::Read 对象解析。

use serde_json::{Result, Value};

fn untyped_example() -> Result<()> {
    // Some JSON input data as a &str. Maybe this comes from the user.
    let data = r#"
        {
            "name": "John Doe",
            "age": 43,
            "phones": [
                "+44 1234567",
                "+44 2345678"
            ]
        }"#;

    // Parse the string of data into serde_json::Value.
    let v: Value = serde_json::from_str(data)?;

    // Access parts of the data by indexing with square brackets.
    println!("Please call {} at the number {}", v["name"], v["phones"][0]);

    Ok(())
}

类似于 v["name"] 的方括号索引的结果是该索引处数据的借用,因此类型是 &Value。JSON 地图可以用字符串键索引,而 JSON 数组可以用整数键索引。如果数据的类型不适合用作索引的类型,或者如果映射不包含要索引的键,或者如果向量的索引超出范围,则返回的元素是 Value::Null

当打印 Value 时,它会被打印为 JSON 字符串。所以在上面的代码中,输出看起来像 请拨打 "John Doe" 的电话号码 "+44 1234567"。引号出现是因为 v["name"] 是一个 &Value,它包含一个 JSON 字符串,其 JSON 表示形式为 "John Doe"。要打印为不带引号的纯字符串,需要将 JSON 字符串转换为 Rust 字符串,使用 as_str() 或避免如以下章节所述使用 Value

Value 表示对于非常基础的任务来说已经足够,但对于更重要的任务来说可能会很繁琐。错误处理实现起来非常冗长,例如,想象一下尝试检测输入数据中未识别字段的Presence。当你犯错时,编译器无法提供帮助,例如,想象一下在代码中几十个地方将 v["name"] 错误地输入为 v["nmae"]

将 JSON 解析为强类型数据结构

Serde 提供了一种强大且高度自动化的方法,将 JSON 数据映射到 Rust 数据结构。

use serde::{Deserialize, Serialize};
use serde_json::Result;

#[derive(Serialize, Deserialize)]
struct Person {
    name: String,
    age: u8,
    phones: Vec<String>,
}

fn typed_example() -> Result<()> {
    // Some JSON input data as a &str. Maybe this comes from the user.
    let data = r#"
        {
            "name": "John Doe",
            "age": 43,
            "phones": [
                "+44 1234567",
                "+44 2345678"
            ]
        }"#;

    // Parse the string of data into a Person object. This is exactly the
    // same function as the one that produced serde_json::Value above, but
    // now we are asking it for a Person as output.
    let p: Person = serde_json::from_str(data)?;

    // Do things just like with any other Rust data structure.
    println!("Please call {} at the number {}", p.name, p.phones[0]);

    Ok(())
}

这是与之前相同的 serde_json::from_str 函数,但这次我们将返回值赋给一个类型为 Person 的变量,这样 Serde 将会自动将输入数据解释为 Person 类型,并在布局不符合 Person 预期格式时产生有意义的错误信息。

任何实现了 Serde 的 Deserialize 特质的类型都可以以这种方式反序列化。这包括 Rust 标准库中的内置类型,如 Vec<T>HashMap<K, V>,以及任何带有 #[derive(Deserialize)] 注解的结构体或枚举。

一旦我们有了类型为 Personp,我们的 IDE 和 Rust 编译器就能像对待其他任何 Rust 代码一样帮助我们正确地使用它。IDE 可以自动补全字段名以防止输入错误,这在 serde_json::Value 表示中是不可能的。Rust 编译器可以检查当我们编写 p.phones[0] 时,则可以保证 p.phones 一定是一个 Vec<String>,因此索引它是有意义的,并产生一个 String

关于使用 Serde 的 derive 宏的必要设置在 Serde 网站的 Using derive 页面上有说明。

构建 JSON 值

Serde JSON 提供了一个 json!,它使用非常自然的 JSON 语法来构建 serde_json::Value 对象。

use serde_json::json;

fn main() {
    // The type of `john` is `serde_json::Value`
    let john = json!({
        "name": "John Doe",
        "age": 43,
        "phones": [
            "+44 1234567",
            "+44 2345678"
        ]
    });

    println!("first phone number: {}", john["phones"][0]);

    // Convert to a string of JSON and print it out
    println!("{}", john.to_string());
}

Value::to_string() 函数将一个 serde_json::Value 转换成一个 JSON 文本的 String

json! 宏的一个优点是,可以在构建 JSON 值的过程中直接将变量和表达式插入其中。Serde 会在编译时检查要插入的值是否能够表示为 JSON。

let full_name = "John Doe";
let age_last_year = 42;

// The type of `john` is `serde_json::Value`
let john = json!({
    "name": full_name,
    "age": age_last_year + 1,
    "phones": [
        format!("+44 {}", random_phone())
    ]
});

这非常方便,但我们又遇到了之前使用 Value 时的问题,即如果使用错误,IDE 和 Rust 编译器无法提供帮助。Serde JSON 提供了一种更好的方法来将强类型数据结构序列化为 JSON 文本。

通过序列化数据结构创建 JSON

可以将数据结构转换为JSON字符串,通过使用serde_json::to_string函数。还有serde_json::to_vec函数,可以将数据序列化为一个Vec<u8>向量,以及serde_json::to_writer函数,可以将数据序列化到任何io::Write类型的对象,例如文件或TCP流。

use serde::{Deserialize, Serialize};
use serde_json::Result;

#[derive(Serialize, Deserialize)]
struct Address {
    street: String,
    city: String,
}

fn print_an_address() -> Result<()> {
    // Some data structure.
    let address = Address {
        street: "10 Downing Street".to_owned(),
        city: "London".to_owned(),
    };

    // Serialize it to a JSON string.
    let j = serde_json::to_string(&address)?;

    // Print, write to a file, or send to an HTTP server.
    println!("{}", j);

    Ok(())
}

任何实现了Serde的Serialize特质的类型都可以以这种方式序列化。这包括内置的Rust标准库类型,如Vec<T>HashMap<K, V>,以及任何使用#[derive(Serialize)]注解的structs或enums。

性能

速度快。您应该期望每秒500到1000兆字节的反序列化速度和600到900兆字节的序列化速度,具体取决于您数据的特点。这与最快的C和C++ JSON库相当,甚至在一些用例中快30%。基准测试可以在serde-rs/json-benchmark存储库中找到。

获取帮助

Serde是最广泛使用的Rust库之一,所以Rustaceans聚集的地方都能帮助您。对于聊天,您可以尝试非官方社区Discord的#general#beginners频道,官方Rust项目Discord的#rust-usage频道,或者在Zulip的#general流。对于异步问题,可以考虑StackOverflow的[rust] tag,Reddit的/r/rust子版块,该版块有一个固定的每周简单问题帖子,或者Rust的Discourse论坛。在这个存储库中提交支持问题是可以接受的,但它们通常不会像上述任何一种方式那样得到很多关注,并且可能在没有回复的情况下一段时间后被关闭。

无标准库支持

只要有一个内存分配器,就可以在不使用Rust标准库的情况下使用serde_json。Rust 1.36+支持这一点。禁用默认的"std"功能并启用"alloc"功能。

[dependencies]
serde_json = { version = "1.0", default-features = false, features = ["alloc"] }

有关Serde中无内存分配器的JSON支持,请参阅serde-json-core存储库。


许可

根据您的选择,该软件受Apache License, Version 2.0MIT license许可。
除非您明确声明,否则根据Apache-2.0许可证定义,您有意提交以包含在本软件包中的任何贡献,应按上述方式双许可,不附加任何额外条款或条件。

依赖项

~530–740KB
~14K SLoC