怎样弄免费网站,青岛网站快速排名提升,装饰工程网站模板下载,国外空间网站源码在 Rust 中使用 Serde 处理json 在本文中#xff0c;我们将讨论 Serde、如何在 Rust 应用程序中使用它以及一些更高级的提示和技巧。
什么是serde#xff1f;
Rust中的serde crate用于高效地序列化和反序列化多种格式的数据。它通过提供两个可以使用的traits来实现这一点我们将讨论 Serde、如何在 Rust 应用程序中使用它以及一些更高级的提示和技巧。
什么是serde
Rust中的serde crate用于高效地序列化和反序列化多种格式的数据。它通过提供两个可以使用的traits来实现这一点这两个traits为 Deserialize 和 Serialize 。作为生态系统中最著名的 crate 之一它目前支持 20 多种类型的序列化反序列化。
首先您需要将 crate 安装到您的 Rust 应用程序中
cargo add serde使用serde
Deserializing and Serializing 数据
序列化和反序列化数据的简单方法是添加 serde derive 功能。这会添加一个宏您可以使用它来自动实现 Deserialize 和 Serialize traits - 您可以使用 --features 标志短的 -F 来实现
cargo add serde -F derive然后我们可以将宏添加到我们想要实现 Deserialize 或 Serialize 的任何结构体或枚举中
use serde::{Deserialize, Serialize};#[derive(Deserialize, Serialize)]
struct MyStruct {message: String,// ... the rest of your fields
}这允许我们使用任何支持 serde 的crate 在所述格式之间进行转换。作为示例让我们使用 serde-json 与 JSON 格式相互转换
use serde_json::json;
use serde::{Deserialize, Serialize};#[derive(Deserialize, Serialize)]
struct MyStruct {message: String,
}fn to_and_from_json() {let json json!({message: Hello world!});let my_struct: MyStruct serde_json::from_str(json).unwrap();assert_eq!(my_struct, MyStruct { message: Hello world!.to_string());assert!(serde_json::to_string(my_struct).is_ok());
}如果您有兴趣在 Rust 应用程序中使用 serde-json 我们有一篇讨论 JSON 解析库的文章您可以在此处查看。
我们还可以对许多源进行反序列化和序列化包括文件流 I/O、JSON 字节数组等。
自定义实现反序列化和序列化
为了更好地理解 serde 在底层是如何工作的我们还可以自定义实现 Deserialize 和 Serialize 。这相当复杂但现在我们将实现一个简单的。下面是序列化 i32 基元类型的简单实现
use serde::{Serializer, Serialize};impl Serialize for i32 {fn serializeS(self, serializer: S) - ResultS::Ok, S::ErrorwhereS: Serializer,{serializer.serialize_i32(*self)}
}为了能够转换类型 serde 内部要求我们使用实现 Serializer 的类型。要为不是原生(primitive)类型 实现 Serialize 我们可以通过序列化为原生(primitive)类型来扩展它然后从原生(primitive)类型转换为我们想要的任何类型。如果我们想要对结构进行自定义序列化我们也可以使用 SerializeStruct trait来执行相同的操作
use serde::ser::{Serialize, Serializer, SerializeStruct};struct Color {r: u8,g: u8,b: u8,
}impl Serialize for Color {fn serializeS(self, serializer: S) - ResultS::Ok, S::ErrorwhereS: Serializer,{// 3 is the number of fields in the struct.let mut state serializer.serialize_struct(Color, 3)?;state.serialize_field(r, self.r)?;state.serialize_field(g, self.g)?;state.serialize_field(b, self.b)?;state.end()}
}注意要序列化字段字段类型还需要实现 Serialize 。如果有未实现 Serialize 的自定义类型则需要实现 Serialize 或使用 Serialize derive宏如果结构体/枚举 类型 包含所有实现 Serialize 的类型。
The Deserialize trait is a little bit different and is a fair bit more complicated to implement. To be able to deserialize to a type, the type itself needs to implement Sized which means that there are a number of types which can’t use this trait (for example str) because they are unsized types. To deserialize a type, you also need to use a type that implements the Visitor trait. Deserialize trait 有点不同并且实现起来要复杂一些。为了能够反序列化为类型类型本身需要实现 Sized 这意味着有许多类型不能使用此特征例如 str 因为它们是unsized 类型。要反序列化类型您还需要使类型实现 Visitor trait。
Visitor trait使用 Rust 中的 Visitor 设计模式。这意味着它封装了一种对相同大小的对象集合进行操作的算法。它允许您编写多种不同的算法来操作数据而无需更改任何原始功能。您可以在这里了解更多相关信息。
下面是一个 MessageVisitor 类型的示例该类型尝试将多种类型反序列化为 String
use std::fmt;use serde::de::{self, Visitor};struct MessageVisitor;implde Visitorde for MessageVisitor {type Value String;fn expecting(self, formatter: mut fmt::Formatter) - fmt::Result {formatter.write_str(A message that can either be deserialized from an i32 or String)}fn visit_stringE(self, value: String) - ResultSelf::Value, EwhereE: de::Error,{Ok(value)}fn visit_strE(self, value: str) - ResultSelf::Value, EwhereE: de::Error,{Ok(value.to_owned())}fn visit_i32E(self, value: i32) - ResultSelf::Value, EwhereE: de::Error,{Ok(value.to_string())}
}正如您所看到的实现的代码量相当大然而它也使我们能够使实现变得更加简单。通过实现 Visitor 特征可以将实现它的类型传递给 Deserialize 方法然后将 JSON 反序列化到我们的结构中
use serde::{Deserialize, Deserializer};implde Deserializede for MyStruct {fn deserializeD(deserializer: D) - ResultSelf, D::ErrorwhereD: Deserializerde,{// note: dont use unwrap in production!let message deserializer.deserialize_string(MessageVisitor).unwrap();Ok(Self { message })}
}您还可以在此处找到有关反序列化结构的文档。但是一般来说建议您使用 derive 功能宏因为手动实现如前面所示代码量相当大。该实现主要涉及使用访问者来访问映射或序列然后迭代元素以将其反序列化。
使用 serde 属性
当涉及到 serde 时crate 还具有许多有用的属性宏我们可以在类型上使用它们以允许在反序列化字段或序列化为结构时进行字段重命名等操作。最好的例子之一是当您与用某种语言编写的 API 进行交互时该语言的键可能是 Rust 中的保留关键字。您可以添加 #[serde(rename)] 属性宏如下所示
use serde::{Deserialize, Serialize};#[derive(Deserialize, Serialize)]
pub struct MyStruct {#[serde(rename type)]kind: String
}这可以让您解决名称冲突的问题
您还可以使用 rename_all 属性将所有字段重命名为另一个大小写
use serde::{Deserialize, Serialize};#[derive(Deserialize, Serialize)]
#[serde(rename_all camelCase)]
pub struct MyStruct {my_message: String
}现在当您序列化此结构时 my_message 应该自动变成 myMessage 非常适合使用以其他语言或不同约定编写的 API。
如果您不想将字段包装在 Option 中您还可以使用 #[serde(default)] 实现默认值。这只是允许用默认值填充字段而不是 报错。您还可以使用 #[serde(default path)] 来指向提供自动默认值的函数。例如这个结构体和函数
use serde::{Deserialize, Serialize};#[derive(Deserialize, Serialize)]
pub struct MyStruct {#[serde(path my_function)]my_message: String,
}fn my_function() - String {Hello world!.to_string()
}serde 还提供其他有用的属性例如能够在结构顶部使用 #[serde(deny_unknown_fields)] 拒绝未知字段。这使您可以确保序列化和反序列化时结构完全按原样。
Deserializing and Serializing enums
让我们看一下这个枚举类型
use serde::{Deserialize, Serialize};#[derive(Deserialize, Serialize)]
enum MyEnum {Data { id: String, data: Value },SomeOtherData { id: i32, name: String }
}请注意在与此枚举进行转换时可以采用两个选项
名为 id 的字符串字段和 data 这是一个 JSON 值可以是map、值或 Json 值可以保存的任何内容名为 id 的 i32 字段和名为 name 的 String 字段
然后您可以匹配枚举变量以进行进一步处理。
当第一个枚举变体用 JSON 编写时您可以看到它应该与此对应
{Data: {id: your_id_here,data: { .. }}
}这种类型的数据是“外部标记的”——这意味着数据的特征是标识符位于 JSON 对象的外部。我们可以添加内联标记以便标识符位于crate的内部 - 让我们看看它会是什么样子
use serde::{Deserialize, Serialize};#[derive(Deserialize, Serialize)]
#[serde(tag type)]
enum MyEnum {Data { id: String, data: Value },SomeOtherData { id: i32, name: String }
}现在 JSON 表示如下所示
{type: Data,id: your_id_here,data: { .. }
}有兴趣内容吗 serde 文档有一个关于tag 的页面您可以在此处Enum representations · Serde找到。
Crates that work well with Serde
serde_with
serde_with 是一个提供自定义反/序列化 帮助程序的包可与 serde 的 with 注释一起使用。通常您可以定义一个模块供反序列化器使用该模块位于用于自定义反序列化的自定义模块之后
#[derive(Deserialize, Serialize)]
pub struct MyStruct {#[serde(with my_module)]my_message: String
}使用 serde_with 时它的工作原理是用名为 serde_as 的新注释替换 with 注释。使用这个新的属性宏您可以做很多事情
使用 Display 和 FromStr traits反序列化类型。支持大于 32 个元素的数组。跳过序列化空选项类型。将逗号分隔的列表反序列化为 VecString 。
要使用 serde_with 您需要手动或使用以下命令将其添加到 Cargo.toml 中
cargo add serde_with然后您需要将 serde_as 添加到您想要使用它的类型如下所示
use serde_with::{serde_as, DisplayFromStr};
#[serde_as]
#[derive(Deserialize, Serialize)]
struct MyStruct {// Serialize with Display, deserialize with FromStr#[serde_as(as DisplayFromStr)]my_number: u8,
}该结构允许您与字符串相互转换但 Rust 结构中的类型本身为 u8 非常有用对吧
这个crate还附带了一个指南您可以使用它来充分利用 serde_with 。总的来说这是 serde 的一个强大的伴侣crate。
serde_bytes
serde_bytes 是一个允许优化处理 [u8] 和 Vecu8 类型的包 - 而 serde 本身能够处理这些类型某些格式可以更有效地反/序列化。使用起来非常简单 - 您只需将其添加到 Cargo.toml 中然后通过 #[serde(with serde_bytes)] 注释添加它如下所示
use serde::{Deserialize, Serialize};#[derive(Deserialize, Serialize)]
struct MyStruct {#[serde(with serde_bytes)]byte_buf: Vecu8,
}总的来说这是一个易于使用且简单的 crate无需太多知识即可提高性能。
尾声
我希望您喜欢阅读有关 Serde 的文章它是一个非常强大的 Rust 包构成了大多数 Rust 应用程序的基础。 Using Serde in Rust