JSON 是一种常用的由键值对组成的数据对象;本文将通过多个例子讲解在 Rust 中如何解析 JSON 内容,以及如何将结构体转换成 JSON 字符串。

Rust searde提供了 JSON 序列化和反序列化的功能;

添加依赖

要使用serde库解析 JSON 文本,你需要添加serdeserde_json依赖到你的项目中;

Cargo.toml文件中添加以下行:

[dependencies]
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"

解析JSON

对未类型化的JSON进行解析

任何有效的 JSON 数据都可以转换成serde_json::Value类型,定义如下:

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

serde_json提供了一些函数用于解析各种形式的 JSON 数据类型:

  • serde_json::from_str,用于解析 JSON 字符串;
  • serde_json::from_slice,用于对字节切片&[u8]进行解析;
  • serde_json::from_reader,从支持io::Read Trait 的对象中读取数据并解析,比如一个文件或 TCP 流;

一个使用serde_json::from_str的例子:

fn main() {

    // 一个&str类型的JSON数据
    let data = r#"
        {
            "name": "James Bond",
            "age": 33,
            "pet_phrase": [
                "Bond, James Bond.",
                "Shaken, not stirred."
            ]
        }"#;

    // 转换成serde_json::Value结构
    let v: serde_json::Value = serde_json::from_str(data).unwrap();

    // 通过方括号建立索引来访问部分数据
    println!("NAME: {}\nAGE: {}\n\t{}\n\t{}",
        v["name"],
        v["age"],
        v["pet_phrase"][0],
        v["pet_phrase"][1],
    );
}

程序运行结果

NAME: "James Bond"
AGE: 33
        "Bond, James Bond."
        "Shaken, not stirred."

将JSON解析到自定义的数据结构

serde提供了SerializeDeserialize这两个 Trait 用于定义数据结构的序列化和反序列化行为;

使用SerializeDeserialize修改前一个例子,使其支持自定义数据结构:

use serde::{Serialize, Deserialize};

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

fn main() {

    // 一个&str类型的JSON数据
    let data = r#"
        {
            "name": "James Bond",
            "age": 33,
            "pet_phrase": [
                "Bond, James Bond.",
                "Shaken, not stirred."
            ]
        }"#;

    // 转换成 Person 结构
    let p: Person = serde_json::from_str(data).unwrap();

    // 通过方括号建立索引来访问部分数据
    println!("NAME: {}\nAGE: {}\n\t{}\n\t{}",
        p.name,
        p.age,
        p.pet_phrase[0],
        p.pet_phrase[1],
    );
}

这段代码运行效果与上一个例子相同,但这一次我们将serde_json::from_str函数的返回值分配给了一个自定义的类型Person

JSON 数据与结构体定义不符时将产生错误;

将数据结构转换成JSON字符串

serde提供一些可以将数据结构转换成JSON数据的函数:

  • serde_json::to_string,将数据结构转换成 JSON 字符串;
  • serde_json::to_vec,将数据结构序列化为Vec<u8>
  • serde_json::to_writer,可以序列化到任何实现了io::Write Trait的对象中,例如文件或 TCP 流;

一个使用serde_json::to_string的例子:

use serde::{Serialize, Deserialize};

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

fn main() {

    let mut pp = Vec::new();
    pp.push("hello world".to_string());
    pp.push("perfcode.com".to_string());

    let p = Person {
        name: "ho".to_string(),
        age: 18,
        pet_phrase: pp,
    };

    // 序列化为JSON字符串
    let s = serde_json::to_string(&p).unwrap();

    println!("{}",s);
    
}

程序运行效果

{"name":"ho","age":18,"pet_phrase":["hello world","perfcode.com"]}

json!宏

serde提供了一个json!宏来非常自然的构建serde_json::Value对象:

.to_string()方法可以将serde_json::Value对象转换成 JSON 字符串;

use serde_json::json;

fn main() {

    let info = json!(
        {
            "name": "James Bond",
            "age": 33,
            "pet_phrase":[
                "Bond, James Bond.",
                "Shaken, not stirred."
                ]
        }
    );

    // 通过方括号建立索引来访问部分数据
    println!("NAME: {}\nAGE: {}\n\t{}\n\t{}",
        info["name"],
        info["age"],
        info["pet_phrase"][0],
        info["pet_phrase"][1],
    );

    //序列化
    println!("{}",info.to_string());

}

程序运行效果

NAME: "James Bond"
AGE: 33
        "Bond, James Bond."
        "Shaken, not stirred."
{"age":33,"name":"James Bond","pet_phrase":["Bond, James Bond.","Shaken, not stirred."]}