serde_json #
1cargo add serde_json
在Rust中,可能会遇到三种常见的需要处理JSON数据的方式:
-
文本数据: 在HTTP端点接收到的、从文件中读取的、或准备发送到远程服务器的未经处理的JSON数据字符串。
-
无类型或松散类型的表示 想在传递某些JSON数据之前验证其有效性,但不需要知道它包含的具体结构。或者想进行一些非常基础的操作,比如在特定位置插入一个键。
-
强类型的Rust数据结构。 期望所有或大部分数据符合特定结构,并且想要在避免JSON松散特性带来麻烦的情况下完成实际工作。
Serde JSON提供了高效、灵活、安全的方法来在这些表示方式之间转换数据。
无类型或松散类型的表示 #
任何有效的JSON数据都可以在以下递归枚举表示中进行操作。这个数据结构是serde_json::Value
。
1enum Value {
2 Null,
3 Bool(bool),
4 Number(Number),
5 String(String),
6 Array(Vec<Value>),
7 Object(Map<String, Value>),
8}
JSON数据字符串可以通过 serde_json::from_str
函数解析成 serde_json::Value
。此外还有 from_slice
用于从字节切片 &[u8]
解析,以及 from_reader
用于从任何 io::Read
(比如文件或 TCP 流)解析。
1use serde_json::{Result, Value};
2
3fn untyped_example() -> Result<()> {
4 // Some JSON input data as a &str. Maybe this comes from the user.
5 let data = r#"
6 {
7 "name": "John Doe",
8 "age": 43,
9 "phones": [
10 "+44 1234567",
11 "+44 2345678"
12 ]
13 }"#;
14
15 // Parse the string of data into serde_json::Value.
16 let v: Value = serde_json::from_str(data)?;
17
18 // Access parts of the data by indexing with square brackets.
19 println!("Please call {} at the number {}", v["name"], v["phones"][0]);
20
21 Ok(())
22}
索引操作如 v["name"]
的结果是该索引处数据的借用,因此其类型是 &Value
。JSON 映射可以用字符串键进行索引,而 JSON 数组可以用整数键进行索引。如果数据类型与索引的类型不匹配,或者映射中不包含所索引的键,或者vector的索引超出范围,则返回的元素是 Value::Null
。
当打印 Value
时,它会被打印为 JSON 字符串。因此在上述代码中,输出看起来像 Please call "John Doe" at the number "+44 1234567"
。这里出现引号是因为 v["name"]
是一个包含 JSON 字符串的 &Value
,其 JSON 表示是 "John Doe"
。如果要打印不带引号的纯字符串,需要使用 as_str()
将 JSON 字符串转换为 Rust 字符串,或者按照下一节所述避免使用 Value
。
Value
表示方式对于非常基础的任务来说是足够的,但对于更重要的任务来说可能会很繁琐。例如,要正确实现错误处理会变得很冗长,比如试图检测输入数据中是否存在未识别的字段。当你犯错时编译器也无法帮助你,例如在代码中的几十个地方中,将 v["name"]
错误地写成 v["nmae"]
。
将JSON解析为强类型数据结构 #
Serde提供了一种强大的方法,能够将JSON数据基本自动地映射到Rust数据结构中。
1
2#[derive(Serialize, Deserialize)]
3struct Person {
4 name: String,
5 age: u8,
6 phones: Vec<String>,
7}
8
9fn typed_example() -> Result<()> {
10 // Some JSON input data as a &str. Maybe this comes from the user.
11 let data = r#"
12 {
13 "name": "John Doe",
14 "age": 43,
15 "phones": [
16 "+44 1234567",
17 "+44 2345678"
18 ]
19 }"#;
20
21 // Parse the string of data into a Person object. This is exactly the
22 // same function as the one that produced serde_json::Value above, but
23 // now we are asking it for a Person as output.
24 let p: Person = serde_json::from_str(data)?;
25
26 // Do things just like with any other Rust data structure.
27 println!("Please call {} at the number {}", p.name, p.phones[0]);
28
29 Ok(())
30}
Serde通过serde_json::from_str
函数实现与之前相同的功能,但这次我们将返回值赋给一个Person
类型的变量,这样Serde就会自动将输入数据解析为Person
类型,并在数据结构与预期的Person
格式不符时生成详细的错误信息。
任何实现了Serde的Deserialize
特征的类型都可以通过这种方式进行反序列化。这包括Rust标准库中的内置类型,如Vec<T>
和HashMap<K, V>
,以及任何使用#[derive(Deserialize)]
标注的结构体或枚举。
一旦我们得到了Person
类型的变量p
,我们的IDE和Rust编译器就能像处理其他Rust代码一样帮助我们正确使用它。IDE可以自动补全字段名称以防止拼写错误,这在serde_json::Value
表示方式中是不可能实现的。而且Rust编译器可以检查当我们写p.phones[0]
时,p.phones
一定是Vec<String>
类型,所以对其进行索引是有意义的,并且会产生一个String
类型的值。
构造JSON值(serde_json::Value
)
#
Serde JSON提供了一个json!
宏,可以使用非常自然的JSON语法来构建serde_json::Value
对象。
1use serde_json::json;
2
3fn main() {
4 // The type of `john` is `serde_json::Value`
5 let john = json!({
6 "name": "John Doe",
7 "age": 43,
8 "phones": [
9 "+44 1234567",
10 "+44 2345678"
11 ]
12 });
13
14 println!("first phone number: {}", john["phones"][0]);
15
16 // Convert to a string of JSON and print it out
17 println!("{}", john.to_string());
18}
Value::to_string()
函数可以将serde_json::Value
转换为JSON格式的String
文本。
json!
宏的一个巧妙之处在于,在构建JSON值时可以直接插入变量和表达式。Serde会在编译时检查你插入的值是否可以表示为JSON。
1let full_name = "John Doe";
2let age_last_year = 42;
3
4// The type of `john` is `serde_json::Value`
5let john = json!({
6 "name": full_name,
7 "age": age_last_year + 1,
8 "phones": [
9 format!("+44 {}", random_phone())
10 ]
11});
这种方式非常方便,但我们遇到了之前使用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流。
1use serde::{Deserialize, Serialize};
2use serde_json::Result;
3
4#[derive(Serialize, Deserialize)]
5struct Address {
6 street: String,
7 city: String,
8}
9
10fn print_an_address() -> Result<()> {
11 // Some data structure.
12 let address = Address {
13 street: "10 Downing Street".to_owned(),
14 city: "London".to_owned(),
15 };
16
17 // Serialize it to a JSON string.
18 let j = serde_json::to_string(&address)?;
19
20 // Print, write to a file, or send to an HTTP server.
21 println!("{}", j);
22
23 Ok(())
24}
任何实现了Serde的Serialize
特征的类型都可以通过这种方式进行序列化。这包括Rust标准库中的内置类型,如Vec<T>
和HashMap<K, V>
,以及任何使用#[derive(Serialize)]
标注的结构体或枚举。