#serde-json #json #serde #serialization

已删除 serde_json_experimental

JSON序列化文件格式

使用旧Rust 2015

1.0.29-rc1 2018年9月20日

#267 in #serde-json

MIT/Apache

390KB
9K SLoC

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

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 用于从字节切片 &[u8] 解析,以及 from_reader 用于从文件或 TCP 流等任何 io::Read 解析。

extern crate serde_json;

use serde_json::{Value, Error};

fn untyped_example() -> Result<(), Error> {
    // 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 字符串的形式打印。所以,在上述代码中,输出看起来像 Please call "John Doe" at the number "+44 1234567"。引号出现是因为 v["name"] 是一个 &Value,它包含一个 JSON 字符串,其 JSON 表示形式是 "John Doe"。打印不带引号的纯字符串涉及将 JSON 字符串转换为 Rust 字符串,使用 as_str 或避免在下一节中描述的方式使用 Value

Value 表示形式对于非常基本的任务已经足够,但对于任何更重要的任务来说,操作起来可能会很繁琐。错误处理实现起来很详细,例如,想象一下尝试检测输入数据中未识别字段的存在。当你犯错时,编译器无法提供帮助,例如,想象一下在代码中数十处使用中把 v["name"] 错误地写成 v["nmae"]

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

Serde 提供了一种强大的方法,可以自动将 JSON 数据映射到 Rust 数据结构中。

extern crate serde;
extern crate serde_json;

#[macro_use]
extern crate serde_derive;

use serde_json::Error;

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

fn typed_example() -> Result<(), Error> {
    // 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

构建 JSON 值

Serde JSON 提供了一个 json!,用于使用非常自然的 JSON 语法构建 serde_json::Value 对象。为了使用此宏,需要使用 #[macro_use] 属性导入 serde_json

#[macro_use]
extern crate serde_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 值的同时直接将变量和表达式插入到 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 流。

extern crate serde;
extern crate serde_json;

#[macro_use]
extern crate serde_derive;

use serde_json::Error;

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

fn print_an_address() -> Result<(), Error> {
    // 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 开发者在 irc.mozilla.org 的 #serde 频道。#rust 频道也是一个很好的资源,通常响应速度更快,但对 Serde 的了解不那么具体。如果您不喜欢 IRC,我们也乐意通过 GitHub issues 进行回复。

无 std 支持

这个crate目前需要 Rust 标准库。要在没有标准库的情况下在 Serde 中支持 JSON,请参阅 serde-json-core crate。

许可协议

Serde JSON 根据 Apache License, Version 2.0 或 MIT 许可协议授权。

您可选其中之一。

贡献

除非您明确声明,否则根据 Apache-2.0 许可协议定义的,您有意提交以包含在 Serde JSON 中的任何贡献,都将按上述方式双授权,不附加任何额外条款或条件。

依赖项

~240–660KB
~13K SLoC