【Rust中的序列化:Serde(一)】

news2024/11/7 3:42:26

Rust中的序列化:Serde

  • Serde是什么?
  • 什么是序列化序列化?
  • Serde运行机制
    • Serde Data Model
    • Vistor Api
    • Serializer Api
    • Deserializer Api
  • 具体示例流程分析
    • 具体步骤:
    • 那么依次这个结论是如何得出的呢?
    • 什么是'de?
  • 总结

Serde是什么?

Serde is a framework for serializing and deserializing Rust data structures efficiently and generically.
名字是序列化和反序列化的缩写,serde就是一种高效且通用的Rust数据结构序列化反序列化框架。


什么是序列化序列化?

序列化指的是将定义的结构化数据转换成更容易存储和或传输的形式,如字节流。而反序列化则是将如流式数据重新恢复成本来的样子,方便开发者解析和处理逻辑。通常情况下序列化反序列化使用在网络通信上。如我们熟知的protobuf等。

Serde运行机制

如下图:
Serde运行机制

Serde Data Model

The Serde data model is the API by which data structures and data formats interact. You can think of it as Serde’s type system.

Serde 数据模型是DataType(DataStruct)与 DataFormat交互的Api,你可以认为它就是Serde的类型系统,
其中包含了Serialze与DeSerialze的Api,同时也有Vistor的Api,可以说,每一种类型的Api都对应了一批Api函数,每一个Api函数又会对应一种类型。
也就是Serde Data Model 是整个转换过程中的中间环节,DataType和DataFormat之间是不互知的,双方都只需要将各自的数据通过Serde Data Model Api转换成Serde Data类型。

Vistor Api

	fn expecting(&self, formatter: &mut Formatter<'_>) -> Result;
    fn visit_bool<E>(self, v: bool) -> Result<Self::Value, E>
       where E: Error { ... }
    fn visit_i8<E>(self, v: i8) -> Result<Self::Value, E>
       where E: Error { ... }
    fn visit_i16<E>(self, v: i16) -> Result<Self::Value, E>
       where E: Error { ... }
    fn visit_i32<E>(self, v: i32) -> Result<Self::Value, E>
       where E: Error { ... }
    fn visit_i64<E>(self, v: i64) -> Result<Self::Value, E>
       where E: Error { ... }
    fn visit_i128<E>(self, v: i128) -> Result<Self::Value, E>
       where E: Error { ... }
    fn visit_u8<E>(self, v: u8) -> Result<Self::Value, E>
       where E: Error { ... }
    fn visit_u16<E>(self, v: u16) -> Result<Self::Value, E>
       where E: Error { ... }
    fn visit_u32<E>(self, v: u32) -> Result<Self::Value, E>
       where E: Error { ... }
    fn visit_u64<E>(self, v: u64) -> Result<Self::Value, E>
       where E: Error { ... }
    fn visit_u128<E>(self, v: u128) -> Result<Self::Value, E>
       where E: Error { ... }
    fn visit_f32<E>(self, v: f32) -> Result<Self::Value, E>
       where E: Error { ... }
    fn visit_f64<E>(self, v: f64) -> Result<Self::Value, E>
       where E: Error { ... }
    fn visit_char<E>(self, v: char) -> Result<Self::Value, E>
       where E: Error { ... }
    fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
       where E: Error { ... }
    fn visit_borrowed_str<E>(self, v: &'de str) -> Result<Self::Value, E>
       where E: Error { ... }
    fn visit_string<E>(self, v: String) -> Result<Self::Value, E>
       where E: Error { ... }
    fn visit_bytes<E>(self, v: &[u8]) -> Result<Self::Value, E>
       where E: Error { ... }
    fn visit_borrowed_bytes<E>(self, v: &'de [u8]) -> Result<Self::Value, E>
       where E: Error { ... }
    fn visit_byte_buf<E>(self, v: Vec<u8>) -> Result<Self::Value, E>
       where E: Error { ... }
    fn visit_none<E>(self) -> Result<Self::Value, E>
       where E: Error { ... }
    fn visit_some<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
       where D: Deserializer<'de> { ... }
    fn visit_unit<E>(self) -> Result<Self::Value, E>
       where E: Error { ... }
    fn visit_newtype_struct<D>(
        self,
        deserializer: D,
    ) -> Result<Self::Value, D::Error>
       where D: Deserializer<'de> { ... }
    fn visit_seq<A>(self, seq: A) -> Result<Self::Value, A::Error>
       where A: SeqAccess<'de> { ... }
    fn visit_map<A>(self, map: A) -> Result<Self::Value, A::Error>
       where A: MapAccess<'de> { ... }
    fn visit_enum<A>(self, data: A) -> Result<Self::Value, A::Error>
       where A: EnumAccess<'de> { ... }

Serializer Api

    // Provided methods
    fn serialize_i128(self, v: i128) -> Result<Self::Ok, Self::Error> { ... }
    fn serialize_u128(self, v: u128) -> Result<Self::Ok, Self::Error> { ... }
    fn collect_seq<I>(self, iter: I) -> Result<Self::Ok, Self::Error>
       where I: IntoIterator,
             <I as IntoIterator>::Item: Serialize { ... }
    fn collect_map<K, V, I>(self, iter: I) -> Result<Self::Ok, Self::Error>
       where K: Serialize,
             V: Serialize,
             I: IntoIterator<Item = (K, V)> { ... }
    fn collect_str<T>(self, value: &T) -> Result<Self::Ok, Self::Error>
       where T: ?Sized + Display { ... }
    fn is_human_readable(&self) -> bool { ... }
	fn serialize_bool(self, v: bool) -> Result<Self::Ok, Self::Error>;
    fn serialize_i8(self, v: i8) -> Result<Self::Ok, Self::Error>;
    fn serialize_i16(self, v: i16) -> Result<Self::Ok, Self::Error>;
    fn serialize_i32(self, v: i32) -> Result<Self::Ok, Self::Error>;
    fn serialize_i64(self, v: i64) -> Result<Self::Ok, Self::Error>;
    fn serialize_u8(self, v: u8) -> Result<Self::Ok, Self::Error>;
    fn serialize_u16(self, v: u16) -> Result<Self::Ok, Self::Error>;
    fn serialize_u32(self, v: u32) -> Result<Self::Ok, Self::Error>;
    fn serialize_u64(self, v: u64) -> Result<Self::Ok, Self::Error>;
    fn serialize_f32(self, v: f32) -> Result<Self::Ok, Self::Error>;
    fn serialize_f64(self, v: f64) -> Result<Self::Ok, Self::Error>;
    fn serialize_char(self, v: char) -> Result<Self::Ok, Self::Error>;
    fn serialize_str(self, v: &str) -> Result<Self::Ok, Self::Error>;
    fn serialize_bytes(self, v: &[u8]) -> Result<Self::Ok, Self::Error>;
    fn serialize_none(self) -> Result<Self::Ok, Self::Error>;
    fn serialize_some<T>(self, value: &T) -> Result<Self::Ok, Self::Error>
       where T: ?Sized + Serialize;
    fn serialize_unit(self) -> Result<Self::Ok, Self::Error>;
    ..

Deserializer Api

fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
       where V: Visitor<'de>;
    fn deserialize_bool<V>(self, visitor: V) -> Result<V::Value, Self::Error>
       where V: Visitor<'de>;
    fn deserialize_i8<V>(self, visitor: V) -> Result<V::Value, Self::Error>
       where V: Visitor<'de>;
    fn deserialize_i16<V>(self, visitor: V) -> Result<V::Value, Self::Error>
       where V: Visitor<'de>;
    fn deserialize_i32<V>(self, visitor: V) -> Result<V::Value, Self::Error>
       where V: Visitor<'de>;
    fn deserialize_i64<V>(self, visitor: V) -> Result<V::Value, Self::Error>
       where V: Visitor<'de>;
    fn deserialize_u8<V>(self, visitor: V) -> Result<V::Value, Self::Error>
       where V: Visitor<'de>;
    fn deserialize_u16<V>(self, visitor: V) -> Result<V::Value, Self::Error>
       where V: Visitor<'de>;
    fn deserialize_u32<V>(self, visitor: V) -> Result<V::Value, Self::Error>
       where V: Visitor<'de>;
    fn deserialize_u64<V>(self, visitor: V) -> Result<V::Value, Self::Error>
       where V: Visitor<'de>;
    fn deserialize_f32<V>(self, visitor: V) -> Result<V::Value, Self::Error>
       where V: Visitor<'de>;
    fn deserialize_f64<V>(self, visitor: V) -> Result<V::Value, Self::Error>
       where V: Visitor<'de>;
    fn deserialize_char<V>(self, visitor: V) -> Result<V::Value, Self::Error>
       where V: Visitor<'de>;
    fn deserialize_str<V>(self, visitor: V) -> Result<V::Value, Self::Error>
       where V: Visitor<'de>;
    fn deserialize_string<V>(self, visitor: V) -> Result<V::Value, Self::Error>
       where V: Visitor<'de>;
    fn deserialize_bytes<V>(self, visitor: V) -> Result<V::Value, Self::Error>
       where V: Visitor<'de>;
    fn deserialize_byte_buf<V>(
        self,
        visitor: V,
    ) -> Result<V::Value, Self::Error>
       where V: Visitor<'de>;
    fn deserialize_option<V>(self, visitor: V) -> Result<V::Value, Self::Error>
       where V: Visitor<'de>;
    fn deserialize_unit<V>(self, visitor: V) -> Result<V::Value, Self::Error>
       where V: Visitor<'de>;
    fn deserialize_unit_struct<V>(
        self,
        name: &'static str,
        visitor: V,
    ) -> Result<V::Value, Self::Error>
       where V: Visitor<'de>;
    fn deserialize_newtype_struct<V>(
        self,
        name: &'static str,
        visitor: V,
    ) -> Result<V::Value, Self::Error>
       where V: Visitor<'de>;
       ...

具体示例流程分析

具体步骤:

  1. 初始化工程:
cargo init whatserde
  1. 将serde引入cargo.toml
serde = { version = "1", features = ["derive"] }
  1. main.rs
use serde::{Deserialize, Serialize};

#[derive(Serialize, Deserialize)]
struct MyTestData {
    a: u64,
    b: String,
}
fn main() {
    println!("Hello, world!");
}
  1. 使用cargo expand展开代码
    没有安装cargo-expand的开发者可根据Link说明安装expandLink
cargo expand > expand.rs

执行后将得到一份展开后的代码如下(部分展示):

  1. 序列化代码:
#[doc(hidden)]
#[allow(non_upper_case_globals, unused_attributes, unused_qualifications)]
const _: () = {
    #[allow(unused_extern_crates, clippy::useless_attribute)]
    extern crate serde as _serde;
    #[automatically_derived]
    impl _serde::Serialize for MyTestData {
        fn serialize<__S>(
            &self,
            __serializer: __S,
        ) -> _serde::__private::Result<__S::Ok, __S::Error>
        where
            __S: _serde::Serializer,
        {
            let mut __serde_state = _serde::Serializer::serialize_struct(
                __serializer,
                "MyTestData",
                false as usize + 1 + 1,
            )?;
            _serde::ser::SerializeStruct::serialize_field(
                &mut __serde_state,
                "a",
                &self.a,
            )?;
            _serde::ser::SerializeStruct::serialize_field(
                &mut __serde_state,
                "b",
                &self.b,
            )?;
            _serde::ser::SerializeStruct::end(__serde_state)
        }
    }
};

可以看到,序列化器先去序列化struct在分别支持序列化字段a和b,最后以end结尾,嵌套类的DataType也是如此,层层递进的序列化最后以end为标识符,表示到达结尾。
2)反序列化代码:

            #[doc(hidden)]
            const FIELDS: &'static [&'static str] = &["a", "b"];
            _serde::Deserializer::deserialize_struct(
                __deserializer,
                "MyTestData",
                FIELDS,
                __Visitor {
                    marker: _serde::__private::PhantomData::<MyTestData>,
                    lifetime: _serde::__private::PhantomData,
                },
            )

观察deserialize_struct 是元组结构体,其中的包含__deserializer反序列化器,结构体名称,字段FILEDS,Visitor访问器,其中,
FILEDS:

const FIELDS: &'static [&'static str] = &["a", "b"];

为Visitor提供了访问顺序,visitor便会按照顺序依次访问下面的字段,在通过反序列化器调用对应的反序列化接口将字段解析,直到没有下一个字段。

那么依次这个结论是如何得出的呢?

代码如下:

#[doc(hidden)]
#[allow(non_upper_case_globals, unused_attributes, unused_qualifications)]
const _: () = {
    #[allow(unused_extern_crates, clippy::useless_attribute)]
    extern crate serde as _serde;
    #[automatically_derived]
    impl<'de> _serde::Deserialize<'de> for MyTestData {
        fn deserialize<__D>(
            __deserializer: __D,
        ) -> _serde::__private::Result<Self, __D::Error>
        where
            __D: _serde::Deserializer<'de>,
        {
            #[allow(non_camel_case_types)]
            #[doc(hidden)]
            enum __Field {
                __field0,
                __field1,
                __ignore,
            }
            #[doc(hidden)]
            struct __FieldVisitor;

可以观察到,有枚举值__filed0,__filed1,__ignore。这侧面印证了serde通过FILEDS顺序来使用__FiledVisitor访问每一个字段并反序列化。
------------------------__ignore是什么?
默认情况下,serde支持序列化方传来的DataType类型有增加(但不能减少),这会大大提高兼容性,(这有点像protobuf中的默认option),反序列化所需要的字段都存在,反序列化就不会出问题。
Serde支持了许多的Attributes,来限制或者扩展:
#[serde(rename = “?”)] 字段重命名。
#[serde(bound = “T : MyTrait”)] 限制只有实现了某种特征才能被序列化反序列化。
#[serde(default)] 即给予字段一个默认值,如果它为空的话。而不是报错。
#[serde(crate= “ …”)],即作为crate引入时可根据此标签重命名依赖包名称和导入。
具体的可以参考这里

什么是’de?

注意到,在反序列化中引入了一个生命周期【'de】,一般情况下,我们常见的生命周期要么是【'static】要么是单字符【`a】

来看看官方给出的解释:

This lifetime is what enables Serde to safely perform efficient zero-copy deserialization across a variety of data formats, something that would be impossible or recklessly unsafe in languages other than Rust.
Zero-copy deserialization means deserializing into a data structure, like the User struct below, that borrows string or byte array data from the string or byte array holding the input. This avoids allocating memory to store a string for each individual field and then copying string data out of the input over to the newly allocated field. Rust guarantees that the input data outlives the period during which the output data structure is in scope, meaning it is impossible to have dangling pointer errors as a result of losing the input data while the output data structure still refers to it.

也就是说,这个因为Rust的生命周期规则,Rust可以安全高效的使用零Copy反序列化方案,而这在其他语言中几乎必然是不安全的。

#[derive(Deserialize)]
struct User<'a> {
    id: u32,
    name: &'a str,
    screen_name: &'a str,
    location: &'a str,
}

Rust保证了在作用于下输入数据的寿命必然输出数据结构的寿命,这意味着在输出结构仍引用它的情况下是不可能出现悬垂指针的,保证了程序的安全和高效。


总结

以上便讨论完毕基本的Serde原理,后续计划会继续讨论如何实现Custom 序列化反序列化。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2229777.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

普通的Java程序员,需要深究源码吗?

作为Java开发者&#xff0c;面试肯定被问过多线程。对于它&#xff0c;大多数好兄弟面试前都是看看八股文背背面试题以为就OK了&#xff1b;殊不知现在的面试官都是针对一个点往深了问&#xff0c;你要是不懂其中原理&#xff0c;面试就挂了。可能你知道什么是进程什么是线程&a…

【vue项目中添加告警音频提示音】

一、前提&#xff1a; 由于浏览器限制不能自动触发音频文件播放&#xff0c;所以实现此类功能时&#xff0c;需要添加触发事件&#xff0c;举例如下&#xff1a; 1、页面添加打开告警声音开关按钮 2、首次进入页面时添加交互弹窗提示&#xff1a;是否允许播放音频 以上两种方…

2024 windos运行程序的时候弹窗:找不到ddl文件【已经解决,只要三步】修复ddl文件

一、错误复现 就是这个错误&#xff0c;网上一顿乱找&#xff0c;也解决不来&#xff0c;不是花钱就是付费就是充会员&#xff01;&#xff01; 二、ddl官网地址下载新的ddl文件&#xff08;自己缺哪个&#xff0c;搜索哪个下载&#xff09; 然灵机一动&#xff0c;ddl肯定有官…

Java并发常见面试题总结(上)

线程 ⭐️什么是线程和进程? 何为进程? 进程是程序的一次执行过程&#xff0c;是系统运行程序的基本单位&#xff0c;因此进程是动态的。系统运行一个程序即是一个进程从创建&#xff0c;运行到消亡的过程 在 Java 中&#xff0c;当我们启动 main 函数时其实就是启动了一…

分类算法——逻辑回归 详解

逻辑回归&#xff08;Logistic Regression&#xff09;是一种广泛使用的分类算法&#xff0c;特别适用于二分类问题。尽管名字中有“回归”二字&#xff0c;逻辑回归实际上是一种分类方法。下面将从底层原理、数学模型、优化方法以及源代码层面详细解析逻辑回归。 1. 基本原理 …

AutoGLM:智谱AI的创新,让手机成为你的生活全能助手

目录 引言一、AutoGLM&#xff1a;开启AI的Phone Use时代二、技术核心&#xff1a;AI从“语言理解”到“执行操作”三、实际应用案例&#xff1a;AutoGLM的智能力量1. 智能生活管理&#x1f34e;2. 社交网络的智能互动&#x1f351;3. 办公自动化&#x1f352;4. 电子商务的购物…

利用ChatGPT完成2024年MathorCup大数据挑战赛-赛道A初赛:台风预测与分析

利用ChatGPT完成2024年MathorCup大数据挑战赛-赛道A初赛&#xff1a;台风预测与分析 引言 在2024年MathorCup大数据挑战赛中&#xff0c;赛道A聚焦于气象数据分析&#xff0c;特别是台风的生成、路径预测、和降水风速特性等内容。本次比赛的任务主要是建立一个分类评价模型&…

Latex中Reference的卷号加粗的问题

找到模板中的.bst文件&#xff0c;查找volume&#xff0c;修改如下 添加bold&#xff0c;卷号会加粗&#xff0c;去掉则正常

国产光耦合器在现代应用中的作用和进步

国产光耦合器已成为各行各业必不可少的元件&#xff0c;有助于确保信号完整性、保护控制系统并提供强大的电气隔离。随着技术的进步&#xff0c;国内制造商提高了光耦合器的质量和可靠性&#xff0c;使其适用于一系列关键应用。本文探讨了国产光耦合器的优势、其应用及其对关键…

《数值分析》实验报告-线性方程组求解

文章目录 1. 实验目标2. 实验内容2.1 设计界面2.2 实现解法2.2.1 高斯消元法2.2.2 克劳斯消元法2.2.3 列主元素法 2.3 结果展示 3. 实现过程3.1 选择并设计算法3.1.1 高斯消元法3.1.2 克劳斯消元法3.1.3 列主元素法 3.2 设计 Tkinter 界面3.3 编写代码实现3.4 结果显示 4. 输入…

SpringBoot接入星火认知大模型

文章目录 准备工作整体思路接入大模型服务端和大模型连接客户端和服务端的连接测试 准备工作 到讯飞星火大模型上根据官方的提示申请tokens 申请成功后可以获得对应的secret&#xff0c;key还有之前创建的应用的appId&#xff0c;这些就是我们要用到的信息 搭建项目 整体思…

使用OpenAI控制大模型的输出(免费)——response_format

免费第三方api-key(硅基流动)使用OpenAI格式&#xff0c;还能控制大模型的输出格式&#xff0c;不能说真香&#xff0c;只能说 真香Plus&#xff01; API-Key领取方法看这篇教程 【1024送福利】硅基流动送2000万token啦&#xff01;撒花✿✿ 附使用教程 支持十几个免费的大模…

Databend 产品月报(2024年10月)

很高兴为您带来 Databend 2024 年 10 月的最新更新、新功能和改进&#xff01;我们希望这些增强功能对您有所帮助&#xff0c;并期待您的反馈。 Databend Cloud&#xff1a;多集群的计算集群 多集群的计算集群会根据工作负载需求自动调整计算资源&#xff0c;添加或移除集群。…

多线程编程与并发控制缓存策略负载均衡数据库优化

本人详解 作者:王文峰,参加过 CSDN 2020年度博客之星,《Java王大师王天师》 公众号:JAVA开发王大师,专注于天道酬勤的 Java 开发问题中国国学、传统文化和代码爱好者的程序人生,期待你的关注和支持!本人外号:神秘小峯 山峯 转载说明:务必注明来源(注明:作者:王文峰…

硅谷甄选(8)spu

Spu模块 SPU(Standard Product Unit)&#xff1a;标准化产品单元。是商品信息聚合的最小单位&#xff0c;是一组可复用、易检索的标准化信息的集合&#xff0c;该集合描述了一个产品的特性。通俗点讲&#xff0c;属性值、特性相同的商品就可以称为一个SPU。 7.1 Spu模块的静态…

【Three.js】SpriteMaterial 加载图片泛白,和原图片不一致

解决方法 如上图所示&#xff0c;整体泛白了&#xff0c;解决方法如下&#xff0c;添加 material.map.colorSpace srgb const imgTexture new THREE.TextureLoader().load(imgSrc)const material new THREE.SpriteMaterial({ map: imgTexture, transparent: true, opacity:…

【高阶数据结构】红黑树的插入

&#x1f921;博客主页&#xff1a;醉竺 &#x1f970;本文专栏&#xff1a;《高阶数据结构》 &#x1f63b;欢迎关注&#xff1a;感谢大家的点赞评论关注&#xff0c;祝您学有所成&#xff01; ✨✨&#x1f49c;&#x1f49b;想要学习更多《高阶数据结构》点击专栏链接查看&a…

CCNA对学历有要求吗?看看你是否有资格报考

思科认证网络助理工程师CCNA作为网络工程领域的权威认证之一&#xff0c;备受年轻人的青睐。然而&#xff0c;对于部分文化水平较低的年轻人来说&#xff0c;他们可能会有一个疑问&#xff1a;CCNA认证对学历有要求吗? 一、CCNA对学历有要求吗? 没有! 针对这一问题&#…

别再盲目选购随身WiFi了!一文教你精准挑选最适合自己的随身WiFi!随身wifi哪个牌子的最好用?

市面上随身WiFi种类繁多&#xff0c;4G/5G&#xff0c;单网设备/三网设备&#xff0c;电池款/USB款/充电宝款等难以抉择。本文旨在为你提供一份详尽的随身WiFi选购指南&#xff01; 首先&#xff0c;明确需求&#xff1a;4G还是5G&#xff1f; 日常用网&#xff0c;如浏览视频…

天锐绿盾加密软件与Ping32:信息安全领域的双子星,谁将引领加密新风尚?

在信息安全这片广袤的星空中&#xff0c;有两颗璀璨的明星格外引人注目&#xff0c;它们就是天锐绿盾加密软件和Ping32。这两款加密软件各自以其卓越的性能、全面的功能和深度的安全保障&#xff0c;赢得了众多企业的青睐。那么&#xff0c;在它们之间&#xff0c;谁将引领加密…