3个稳定版本
1.1.65 | 2021年7月18日 |
---|---|
1.1.64 | 2021年5月25日 |
1.0.64+20210523 | 2021年5月23日 |
#581 在 编码
每月120次下载
在 2 crates 中使用
530KB
12K SLoC
Serde JSON
Serde是一个用于高效和通用地序列化和反序列化Rust数据结构的框架。
[dependencies]
serde_partiql = "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_partiql::Value
。
enum Value {
Null,
Bool(bool),
Number(Number),
String(String),
Array(Vec<Value>),
Object(Map<String, Value>),
}
可以使用 serde_partiql::from_str
函数将JSON数据字符串解析为 serde_partiql::Value
。还有 from_slice
用于从字节数组解析,以及 from_reader
用于从任何类似文件或TCP流的数据源解析。
use serde_partiql::{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_partiql::Value.
let v: Value = serde_partiql::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字符串的形式打印。因此,在上述代码中,输出看起来像 请调用 "John Doe" 在号码 "+44 1234567"
。引号出现是因为 v["name"]
是一个包含JSON字符串的 &Value
,它的JSON表示是 "John Doe"
。作为不带引号的普通字符串打印涉及将JSON字符串转换为Rust字符串,使用 as_str()
或避免在下一节中描述的方式使用 Value
。
Value
表示对于非常基础的任务来说是足够的,但对于更重要的任务来说可能会很麻烦。错误处理实现起来很冗长,例如,想象一下尝试检测输入数据中未识别字段的存在。当你犯错时,编译器无法帮助你,例如,想象一下在代码中成百上千次使用时将 v["name"]
错误地拼写成 v["nmae"]
。
将JSON解析为强类型数据结构
Serde提供了一种强大的方法,可以自动将JSON数据映射到Rust数据结构。
use serde::{Deserialize, Serialize};
use serde_partiql::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_partiql::Value above, but
// now we are asking it for a Person as output.
let p: Person = serde_partiql::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_partiql::from_str
函数,但这次我们将返回值赋给一个类型为 Person
的变量,这样 Serde 就会自动将输入数据解释为 Person
,如果布局不符合预期的 Person
形式,将产生有意义的错误信息。
任何实现了 Serde 的 Deserialize
特性的类型都可以这样反序列化。这包括 Rust 标准库中的内置类型,如 Vec<T>
和 HashMap<K, V>
,以及任何使用 #[derive(Deserialize)]
注解的结构体或枚举。
一旦我们有了类型为 Person
的 p
,我们的 IDE 和 Rust 编译器就可以像处理任何其他 Rust 代码一样帮助我们正确使用它。IDE 可以自动完成字段名以防止拼写错误,这在 serde_partiql::Value
表示中是不可能的。Rust 编译器可以检查当我们编写 p.phones[0]
时,p.phones
被保证为一个 Vec<String>
,因此对它的索引是有意义的,并产生一个 String
。
使用 Serde derive 宏的必要设置在 Serde 网站的 使用 derive 页面上有说明。
构造 JSON 值
Serde JSON 提供了一个 json!
宏,可以非常自然地使用 JSON 语法构建 serde_partiql::Value
对象。
use serde_partiql::json;
fn main() {
// The type of `john` is `serde_partiql::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_partiql::Value
转换为 JSON 文本的 String
。
json!
宏的一个巧妙之处在于,变量和表达式可以直接在构建 JSON 值时插入。Serde 将在编译时检查您正在插值的值是否可以表示为 JSON。
let full_name = "John Doe";
let age_last_year = 42;
// The type of `john` is `serde_partiql::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_partiql::to_string
转换为JSON字符串。还有serde_partiql::to_vec
,它序列化为Vec<u8>
,以及serde_partiql::to_writer
,它可以序列化到任何io::Write
,例如文件或TCP流。
use serde::{Deserialize, Serialize};
use serde_partiql::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_partiql::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的#general或#beginners频道,官方Rust项目Discord的#rust-usage频道,或者在Zulip中的#general流。对于异步问题,可以考虑StackOverflow上的[rust]标签,/r/rust subreddir,它有一个固定的每周简单问题帖子,或者Rust Discourse论坛。在此存储库中提交支持问题是可以接受的,但它们通常不会像上述任何一种那样得到那么多关注,并且可能在没有回应的情况下关闭。
无std支持
只要存在内存分配器,就可以在不使用Rust标准库的情况下使用serde_partiql。这从Rust 1.36+开始支持。禁用默认的"std"功能并启用"alloc"功能。
[dependencies]
serde_partiql = { version = "1.0", default-features = false, features = ["alloc"] }
有关在没有内存分配器的情况下使用Serde进行JSON支持的详细信息,请参阅serde-json-core
存储库。
许可证
根据您的选择,在Apache License,Version 2.0或MIT许可证下授权。除非您明确声明,否则您提交给此存储库的任何有意提交的贡献,根据Apache-2.0许可证的定义,应如上所述双重许可,而不附加任何额外的条款或条件。
依赖关系
~165–620KB
~12K SLoC