当前位置:网站首页>Rust 入门指南(使用JSON)

Rust 入门指南(使用JSON)

2022-08-09 12:12:00 InfoQ

JSON 作为使用最广泛的数据结构,学习了解如何在发展最快的 Rust 语言中使用很有必要。
本文中我们将学习到:
  • 读取无类型的 JSON。
  • 将 JSON 读取为强类型数据结构。
  • 写 JSON 字符串。
使用 
serde
 和 
serde-json
 Rust 依赖。

无类型 JSON

Rust 是强类型语言,而 JSON 的并没有强制制定自己的数据类型。如果我们不关心 JSON 的数据结构,可以使用
serde_json
 库将 JSON 当作枚举递归使用。这个结构可以接受 bools, string, numbers, arrays, 和对象(以及 null )。
接下来,我们给我们的新项目(
cargo new handle_json
)添加相应依赖:
serde_json = "1.0"
serde = { version = "1.0", features = ["derive"] }
To handle untyped JSON values, we will use 
from_str()
 function provided by the 
serde_json
 dependency. Additionally, we will need to use the Enum representation I talked about previously to parse the values.
serde_json
 提供的 
from_str()
 方法可以处理无类型 JSON 值,JSON 数据会被处理成枚举的形式。
use serde_json::{Value};

fn main() {
    let json = r#"
{
  "article": "how to work with json in Rust",
  "author": "tdep",
  "paragraph": [
    {
      "name": "untyped"
    },
    {
      "name": "strongly typed"
    },
    {
      "name": "writing json"
    }
  ]
}
"#;
    let parsed: Value = read_json(json);

    println!("\n\n The title of the article is {}", parsed["article"])
}

fn read_json(raw_json:&str) -> Value {
    let parsed: Value = serde_json::from_str(raw_json).unwrap();
    return parsed
}
上面代码的 
read_json
 函数为解析 JSON 函数,它将字符串处理成 JSON。首先使用
serde_json::from_str()
 解析字符串,然后解包。如果我们要访问 JSON 中的字段 ,可以使用类似
parsed["article"]
 这样的代码。

有类型的 JSON

大部分情况下,我们需要使用安全的数据类型在我们的程序中。
serde
 提供了一个很棒的方法,可以把 JSON 数据映射到 Rust 语言结构。使用方式和上一个例子相似,但是不需要使用 Enum 类型,而是分配一个原生的 Rust 数据结构。
serde
 在反序列化时可以检查 JSON 数据类型并匹配,例子如下:
use serde::{Deserialize, Serialize};

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

#[derive(Serialize, Deserialize)]
struct Article {
    article: String,
    author: String,
&nbsp;&nbsp;&nbsp;&nbsp;paragraph:&nbsp;Vec<Paragraph>
}

fn&nbsp;main()&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;let&nbsp;json&nbsp;=&nbsp;r#&quot;
{
&nbsp;&nbsp;&quot;article&quot;:&nbsp;&quot;how&nbsp;to&nbsp;work&nbsp;with&nbsp;json&nbsp;in&nbsp;Rust&quot;,
&nbsp;&nbsp;&quot;author&quot;:&nbsp;&quot;tdep&quot;,
&nbsp;&nbsp;&quot;paragraph&quot;:&nbsp;[
&nbsp;&nbsp;&nbsp;&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&quot;name&quot;:&nbsp;&quot;untyped&quot;
&nbsp;&nbsp;&nbsp;&nbsp;},
&nbsp;&nbsp;&nbsp;&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&quot;name&quot;:&nbsp;&quot;strongly&nbsp;typed&quot;
&nbsp;&nbsp;&nbsp;&nbsp;},
&nbsp;&nbsp;&nbsp;&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&quot;name&quot;:&nbsp;&quot;writing&nbsp;json&quot;
&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;]
}
&quot;#;
&nbsp;&nbsp;&nbsp;&nbsp;let&nbsp;parsed:&nbsp;Article&nbsp;=&nbsp;read_json_typed(json);

&nbsp;&nbsp;&nbsp;&nbsp;println!(&quot;\n\n&nbsp;The&nbsp;name&nbsp;of&nbsp;the&nbsp;first&nbsp;paragraph&nbsp;is:&nbsp;{}&quot;,&nbsp;parsed.paragraph[0].name);
}

fn&nbsp;read_json_typed(raw_json:&nbsp;&str)&nbsp;->&nbsp;Article&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;let&nbsp;parsed:&nbsp;Article&nbsp;=&nbsp;serde_json::from_str(raw_json).unwrap();
&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;parsed
&nbsp;&nbsp;&nbsp;&nbsp;
}
和第一个例子有三处不同:第一,是我们定义两个
serde
&nbsp;的序列号/反序列化的结构;然后我读取 JSON 数据结构指定&nbsp;
Article
&nbsp;对象作为类型;第三,我们读取解析结构使用的不是 Emun方式,而是&nbsp;
struct
&nbsp;:&nbsp;
parsed.paragraph[0].name
&nbsp;。
现在我们可以指定具体的类型和名称读JSON 内容。
但如果我们提供的 JSON 数据和结构不匹配的话:
{
&nbsp;&nbsp;&quot;article&quot;:&nbsp;&quot;how&nbsp;to&nbsp;work&nbsp;with&nbsp;json&nbsp;in&nbsp;Rust&quot;,
&nbsp;&nbsp;&quot;author&quot;:&nbsp;&quot;tdep&quot;,
&nbsp;&nbsp;&quot;paragraph&quot;:&nbsp;[
&nbsp;&nbsp;&nbsp;&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&quot;name&quot;:&nbsp;1
&nbsp;&nbsp;&nbsp;&nbsp;},
&nbsp;&nbsp;&nbsp;&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&quot;name&quot;:&nbsp;&quot;strongly&nbsp;typed&quot;
&nbsp;&nbsp;&nbsp;&nbsp;},
&nbsp;&nbsp;&nbsp;&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&quot;name&quot;:&nbsp;&quot;writing&nbsp;json&quot;
&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;]
}
我们把 JSON 中的第一个&nbsp;
name
&nbsp;字段改成数字,程序会出错:
thread&nbsp;'main'&nbsp;panicked&nbsp;at&nbsp;'called&nbsp;`Result::unwrap()`&nbsp;on&nbsp;an&nbsp;`Err`&nbsp;value:&nbsp;Error(&quot;invalid&nbsp;type:&nbsp;integer&nbsp;`1`,&nbsp;expected&nbsp;a&nbsp;string&quot;,&nbsp;line:&nbsp;8,&nbsp;column:&nbsp;15)',&nbsp;src/main.rs:44:58
或者我们把
“article”
&nbsp;key 改成&nbsp;
“name”
&nbsp;:
{
&nbsp;&nbsp;&quot;name&quot;:&nbsp;&quot;how&nbsp;to&nbsp;work&nbsp;with&nbsp;json&nbsp;in&nbsp;Rust&quot;,
&nbsp;&nbsp;&quot;author&quot;:&nbsp;&quot;tdep&quot;,
&nbsp;&nbsp;&quot;paragraph&quot;:&nbsp;[
&nbsp;&nbsp;&nbsp;&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&quot;name&quot;:&nbsp;&quot;untyped&quot;
&nbsp;&nbsp;&nbsp;&nbsp;},
&nbsp;&nbsp;&nbsp;&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&quot;name&quot;:&nbsp;&quot;strongly&nbsp;typed&quot;
&nbsp;&nbsp;&nbsp;&nbsp;},
&nbsp;&nbsp;&nbsp;&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&quot;name&quot;:&nbsp;&quot;writing&nbsp;json&quot;
&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;]
}
程序也会出错:
thread&nbsp;'main'&nbsp;panicked&nbsp;at&nbsp;'called&nbsp;`Result::unwrap()`&nbsp;on&nbsp;an&nbsp;`Err`&nbsp;value:&nbsp;Error(&quot;missing&nbsp;field&nbsp;`article`&quot;,&nbsp;line:&nbsp;17,&nbsp;column:&nbsp;1)',&nbsp;src/main.rs:44:58
因为,Rust 无法检测 JSON 中的&nbsp;
article
&nbsp;字段。
这是一种更好的接收 JSON 数据的办法。
接下来让我们看下如何反过来操作:从 Rust 数据结构到 JSON 字符串。

写JSON

我们将使用&nbsp;
serde_json::to_string()
&nbsp;函数将数据结构转换为 JSON 字符串,并使用 serde 的&nbsp;
Serialize
使结构能够被序列化。 让我们看一个例子:
use&nbsp;serde::{Deserialize,&nbsp;Serialize};

#[derive(Serialize,&nbsp;Deserialize)]
struct&nbsp;Paragraph&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;name:&nbsp;String
}

#[derive(Serialize,&nbsp;Deserialize)]
struct&nbsp;Article&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;article:&nbsp;String,
&nbsp;&nbsp;&nbsp;&nbsp;author:&nbsp;String,
&nbsp;&nbsp;&nbsp;&nbsp;paragraph:&nbsp;Vec<Paragraph>
}

fn&nbsp;main()&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;let&nbsp;article:&nbsp;Article&nbsp;=&nbsp;Article&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;article:&nbsp;String::from(&quot;how&nbsp;to&nbsp;work&nbsp;with&nbsp;json&nbsp;in&nbsp;Rust&quot;),
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;author:&nbsp;String::from(&quot;tdep&quot;),
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;paragraph:&nbsp;vec![
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Paragraph&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;name:&nbsp;String::from(&quot;untyped&quot;)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;},
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Paragraph&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;name:&nbsp;String::from(&quot;strongly&nbsp;typed&quot;)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;},
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Paragraph&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;name:&nbsp;String::from(&quot;writing&nbsp;json&quot;)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;]
&nbsp;&nbsp;&nbsp;&nbsp;};

&nbsp;&nbsp;&nbsp;&nbsp;let&nbsp;json&nbsp;=&nbsp;serde_json::to_string(&article).unwrap();

&nbsp;&nbsp;&nbsp;&nbsp;println!(&quot;the&nbsp;JSON&nbsp;is:&nbsp;{}&quot;,&nbsp;json)
}
我们构建&nbsp;
Article
,然后将其引用传递给&nbsp;
serde_json::to_string()
&nbsp;函数。 运行 cargo 项目的结果:
the&nbsp;JSON&nbsp;is:&nbsp;{&quot;article&quot;:&quot;how&nbsp;to&nbsp;work&nbsp;with&nbsp;json&nbsp;in&nbsp;Rust&quot;,&quot;author&quot;:&quot;tdep&quot;,&quot;paragraph&quot;:[{&quot;name&quot;:&quot;untyped&quot;},{&quot;name&quot;:&quot;strongly&nbsp;typed&quot;},{&quot;name&quot;:&quot;writing&nbsp;json&quot;}]}
我们已经了解了如何在 Rust 中以快速、安全和高效的方式处理 JSON。 还值得一提的是,我们使用&nbsp;
serde_json::from_string
&nbsp;或&nbsp;
serde_json::to_string
&nbsp;完成的每个操作,也可以使用&nbsp;
serde_json::to_vec
,&nbsp;
serde_json::to_writer
&nbsp;不同的是:
to_vec
&nbsp;序列化 (或反序列化)到一个vector,以及
to_writer
&nbsp;到任何可写的输出(例如一个文件)。

加入 GeekCode Community 参与定义 Cloud Based IDE
null


原网站

版权声明
本文为[InfoQ]所创,转载请带上原文链接,感谢
https://xie.infoq.cn/article/9a3d5233898f6492e4528f909