127 个稳定版本
新 1.0.127 | 2024 年 8 月 23 日 |
---|---|
1.0.121 | 2024 年 7 月 28 日 |
1.0.115 | 2024 年 3 月 26 日 |
1.0.108 | 2023 年 10 月 30 日 |
0.6.0 | 2015 年 8 月 31 日 |
6 在 编码 中
14,030,484 每月下载量
在 49,981 个 crate (27,750 直接) 中使用
560KB
13K SLoC
Serde JSON −
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::Value
,这通过serde_json::from_str
函数实现。还有from_slice
函数用于从字节切片&[u8]
中解析,以及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"
。若要作为不带引号的普通字符串打印,需要使用as_str()
方法从JSON字符串转换为Rust字符串,或避免使用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)]
注释的结构体或枚举。
一旦我们有了类型为 Person
的 p
,我们的 IDE 和 Rust 编译器可以帮助我们像使用任何其他 Rust 代码一样正确使用它。IDE 可以自动完成字段名以防止拼写错误,这在 serde_json::Value
表示中是不可能实现的。Rust 编译器还可以检查当我们编写 p.phones[0]
时,则 p.phones
一定是 Vec<String>
类型,因此索引它是有意义的并返回一个 String
。
有关使用 Serde derive 宏的必要设置,请参阅 Serde 网站的 使用 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(邀请链接:https://discord.gg/rust-lang-community)的 #rust-questions 或 #rust-beginners 频道,官方 Rust 项目 Discord 的 #rust-usage 或 #beginners 频道(邀请链接:https://discord.gg/rust-lang),或在 Zulip 的 #general 流。对于异步问题,可以考虑 StackOverflow 上的 [rust] 标签、/r/rust subreddits,它每周都有一个固定的简单问题帖子,或者 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许可证定义,您有意提交给本软件仓库的贡献将被双重许可,如上所述,不附加任何额外条款或条件。
依赖关系
~0.3–0.8MB
~15K SLoC