15个稳定版本

1.0.108 2023年10月30日
1.0.107 2023年9月13日
1.0.105 2023年8月15日
1.0.104 2023年7月26日
1.0.95 2023年3月27日

#119 in 编码

Download history 138/week @ 2024-04-08 71/week @ 2024-04-15 37/week @ 2024-04-22 37/week @ 2024-04-29 219/week @ 2024-05-06 109/week @ 2024-05-13 2/week @ 2024-05-20 76/week @ 2024-05-27 23/week @ 2024-06-03 25/week @ 2024-06-10 21/week @ 2024-06-17 39/week @ 2024-06-24 9/week @ 2024-07-01 64/week @ 2024-07-08 615/week @ 2024-07-15 462/week @ 2024-07-22

1,152 每月下载量
tyedev 中使用

MIT/Apache

550KB
13K SLoC

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

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数据时,你可能会有三种常见的方法。

  • 作为文本数据。 在HTTP端点接收到的未处理JSON数据字符串,从文件中读取或准备发送到远程服务器。
  • 作为无类型或松散类型的表示。 你可能希望在传递之前检查某些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>),
}

可以将字符串形式的JSON数据通过serde_json::from_str函数解析成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字符串。所以在上面的代码中,输出看起来像请在电话号码"+44 1234567"上呼叫"John Doe"。引号出现是因为v["name"]是一个包含JSON字符串的&Value,其JSON表示是"John Doe"。打印为不带引号的普通字符串需要将JSON字符串转换为Rust字符串,使用as_str()或避免使用Value,如下一节所述。

Value表示对于非常基本的任务来说足够了,但对于更重大的任务来说,操作起来可能会很繁琐。错误处理实现起来很详细,例如,想象一下尝试检测输入数据中未识别字段的存在的场景。当你犯错时,编译器无法帮助你,例如,想象一下在代码中数十个位置之一将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)] 注解的结构体或枚举。

一旦我们有 p 类型的 Person,我们的 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

数据结构可以通过 serde_json::to_string 方法转换为 JSON 字符串。还有 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)] 注解的结构体或枚举。

性能

它很快。您应该期待每秒大约 500 到 1000 兆字节的反序列化速度和 600 到 900 兆字节的序列化速度,具体取决于您的数据特征。这与其他最快的 C 和 C++ JSON 库具有竞争力,甚至在许多情况下比它们快 30%。基准测试在 serde-rs/json-benchmark 仓库中。

获取帮助

Serde 是最广泛使用的 Rust 库之一,因此任何 Rustaceans 聚集的地方都可能会帮助您。对于聊天,可以考虑尝试非官方社区 Discord 的 #rust-questions#rust-beginners 频道(邀请链接:https://discord.gg/rust-lang-community),官方 Rust 项目 Discord 的 #rust-usage#beginners 频道(邀请链接:https://discord.gg/rust-lang),或在 Zulip 的 #general 流。对于异步,可以考虑 StackOverflow 上的 [rust] 标签、/r/rust 子论坛(每周有固定的问题帖子),或 Rust 的 Discourse 论坛。您可以在本仓库中提交支持问题,但它们通常不会像上述任何一种那样得到很多关注,并且在一段时间后可能被关闭。

无标准支持

只要有内存分配器,就可以在不使用 Rust 标准库的情况下使用 serde_json。禁用默认的 "std" 特性并启用 "alloc" 特性

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

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


许可证

根据您的选择,许可协议为 Apache License,Version 2.0 或 MIT 许可证。
除非您明确表示,否则您根据Apache-2.0许可证定义的任何有意提交以包含在此软件包中的贡献,均应按上述方式双授权,不得附加任何额外条款或条件。

依赖项

~155–590KB
~12K SLoC