当前位置: 首页 > news >正文

【跟小嘉学 Rust 编程】二十六、Rust的序列化解决方案(Serde)

系列文章目录

【跟小嘉学 Rust 编程】一、Rust 编程基础
【跟小嘉学 Rust 编程】二、Rust 包管理工具使用
【跟小嘉学 Rust 编程】三、Rust 的基本程序概念
【跟小嘉学 Rust 编程】四、理解 Rust 的所有权概念
【跟小嘉学 Rust 编程】五、使用结构体关联结构化数据
【跟小嘉学 Rust 编程】六、枚举和模式匹配
【跟小嘉学 Rust 编程】七、使用包(Packages)、单元包(Crates)和模块(Module)来管理项目
【跟小嘉学 Rust 编程】八、常见的集合
【跟小嘉学 Rust 编程】九、错误处理(Error Handling)
【跟小嘉学 Rust 编程】十一、编写自动化测试
【跟小嘉学 Rust 编程】十二、构建一个命令行程序
【跟小嘉学 Rust 编程】十三、函数式语言特性:迭代器和闭包
【跟小嘉学 Rust 编程】十四、关于 Cargo 和 Crates.io
【跟小嘉学 Rust 编程】十五、智能指针(Smart Point)
【跟小嘉学 Rust 编程】十六、无畏并发(Fearless Concurrency)
【跟小嘉学 Rust 编程】十七、面向对象语言特性
【跟小嘉学 Rust 编程】十八、模式匹配(Patterns and Matching)
【跟小嘉学 Rust 编程】十九、高级特性
【跟小嘉学 Rust 编程】二十、进阶扩展
【跟小嘉学 Rust 编程】二十一、网络编程
【跟小嘉学 Rust 编程】二十三、Cargo 使用指南
【跟小嘉学 Rust 编程】二十四、内联汇编(inline assembly)
【跟小嘉学 Rust 编程】二十五、Rust命令行参数解析库(clap)
【跟小嘉学 Rust 编程】二十六、Rust的序列化解决方案(Serde)

文章目录

  • 系列文章目录
    • @[TOC](文章目录)
  • 前言
  • 一、Serde 介绍
    • 1.1、Serde 介绍
    • 1.2、添加依赖
    • 1.3、快速开始
  • 二、属性
    • 2.1、Container attributes
      • 2.1.1、#[serde(rename = "name")]
      • 2.1.2、#[serde(rename_all = "...")]
      • 2.1.3、##[serde(deny_unknown_fields)]
      • 2.1.4、#[serde(tag = "type")]
      • 2.1.5、#[serde(tag = "t", content = "c")]
      • 2.1.6、#[serde(untagged)]
      • 2.1.7、#[serde(bound = "T: MyTrait")]
      • 2.1.8、#[serde(default)]
      • 2.1.9、#[serde(default = "path")]
      • 2.1.10、#[serde(remote = "...")]
      • 2.1.11、#[serde(transparent)]
      • 2.1.12、#[serde(from = "FromType")]
      • 2.1.13、#[serde(try_from = "FromType")]
      • 2.1.14、#[serde(into = "IntoType")]
      • 2.1.15、#[serde(crate = "...")]
      • 2.1.16、#[serde(expecting = "...")]
    • 2.2、变量属性
      • 2.2.1、#[serde(rename = "name")]
      • 2.2.2、#[serde(alias = "name")]
      • 2.2.3、#[serde(rename_all = "...")]
      • 2.2.4、#[serde(skip)]
      • 2.2.5、#[serde(skip_serializing)]
      • 2.2.6、#[serde(skip_deserializing)]
      • 2.2.7、#[serde(serialize_with = "path")]
      • 2.2.8、#[serde(deserialize_with = "path")]
      • 2.2.9、#[serde(with = "module")]
      • 2.2.10、#[serde(bound = "T: MyTrait")]
      • 2.2.11、#[serde(borrow)] and #[serde(borrow = "'a + 'b + ...")]
      • 2.2.12、#[serde(other)]
    • 2.3、自段属性
      • 2.3.1、#[serde(rename = "name")]
      • 2.3.2、#[serde(alias = "name")]
      • 2.3.3、#[serde(default)]
      • 2.3.4、#[serde(default = "path")]
      • 2.3.5、#[serde(flatten)]
      • 2.3.6、#[serde(skip)]
      • 2.3.7、#[serde(skip_serializing)]
      • 2.3.8、#[serde(skip_deserializing)]
      • 2.3.9、#[serde(skip_serializing_if = "path")]
      • 2.3.10、#[serde(serialize_with = "path")]
      • 2.3.11、#[serde(deserialize_with = "path")]
      • 2.3.12、#[serde(with = "module")]
      • 2.3.13、#[serde(borrow)] and #[serde(borrow = "'a + 'b + ...")]
      • 2.3.14、#[serde(bound = "T: MyTrait")]
      • 2.3.3、#[serde(getter = "...")]
  • 三、自定义序列化
    • 3.1、实现序列化
    • 3.1.1、Serialize
    • 3.1.2、原始类型
    • 3.1.3、序列化结构体
    • 3.2、实现反序列化
      • 3.2.1、反序列化 trait
      • 3.2.2、Visitor trait
    • 3.3、单元测试
  • 四、写一个数据格式
    • 4.1、约定
    • 4.2、错误处理
    • 4.3、实现序列化
    • 4.3、实现反序列化
  • 五、反序列化生命周期
    • 5.1、理解反序列化生命周期
    • 5.2、trait 边界
    • 5.3、暂态(Transient)、借用(borrowed)和拥有的数据(owned data)
      • 5.3.1、暂态(Transient)
      • 5.3.2、借用(Borrowed)
      • 5.3.3、拥有(Owned)

前言

本章节讲解的 Rust 序列化解决方案是以 serde 为中心的,包含了 serde、serde_json、serde_yaml等第三方库的使用

主要教材参考 《The Rust Programming Language》
主要教材参考 《Rust For Rustaceans》
主要教材参考 《The Rustonomicon》
主要教材参考 《Rust 高级编程》
主要教材参考 《Cargo 指南》


一、Serde 介绍

1.1、Serde 介绍

Serde 是建立在 Rust 的 trait 系统之上的,实现 Serialize 和 Deserialize 可以帮助我们实现序列化和反序列化。

支持的数据格式有:JSON、YAML、TOML等等。

1.2、添加依赖

cargo add serde --features derive
cargo add serde_json serde_yaml

1.3、快速开始

use serde::{Serialize, Deserialize};#[derive(Serialize, Deserialize, Debug)]
struct Point {x: i32,y: i32,
}fn main() {let point = Point { x: 1, y: 2 };let serialized = serde_json::to_string(&point).unwrap();println!("serialized = {}", serialized);let deserialized: Point = serde_json::from_str(&serialized).unwrap();println!("deserialized = {:?}", deserialized);
}

执行结果

cargo run
serialized = {"x":1,"y":2}
deserialized = Point { x: 1, y: 2 }

二、属性

使用属性可以帮助我们自定义 序列化和序列化, 常见的属性包括如下几种

  • 包含的属性:应用在结构体或枚举声明
  • 变量属性:应用在枚举变量中
  • 字段属性:应用在结构体或枚举种的一个字段;

2.1、Container attributes

2.1.1、#[serde(rename = “name”)]

使用给定的名称为结构体和枚举序列化和反序列化。支持单独为序列化或反序列化设置。

2.1.2、#[serde(rename_all = “…”)]

重命名结构体的字段或者枚举的变体根据给定约定的情况。可能值包含如下几种

  • lowercase:小写
  • UPPERCASE:大写
  • PascalCase:帕斯卡命名
  • camelCase:驼峰命名法
  • snake_case:蛇形命名法,使用下划线分隔
  • SCREAMING_SNAKE_CASE:大写蛇形命名法
  • kebab-case:破折号命名
  • SCREAMING-KEBAB-CASE:大写破折号命名

支持单独为序列化或反序列化设置。

2.1.3、##[serde(deny_unknown_fields)]

在反序列化的过程中遇到未知的自段总是报错。当属性不存在时,默认情况下不会忽略自描述格式的未知自段。

注意:该属性不支持 flatten 结合

2.1.4、#[serde(tag = “type”)]

在枚举上使用带给顶标记的内部标记枚举表示形式。在将结构体的名称序列化为给定键的自段,位于结构体的所有实际自段的前面。

2.1.5、#[serde(tag = “t”, content = “c”)]

对枚举使用领接标记的枚举表示,并标记和内容使用给定的字段名。

2.1.6、#[serde(untagged)]

对枚举使用无标记的枚举表示。

2.1.7、#[serde(bound = “T: MyTrait”)]

设置序列化和反序列化的 Traint 边界。

2.1.8、#[serde(default)]

为结构体设置默认的反序列化标记。

2.1.9、#[serde(default = “path”)]

2.1.10、#[serde(remote = “…”)]

2.1.11、#[serde(transparent)]

2.1.12、#[serde(from = “FromType”)]

2.1.13、#[serde(try_from = “FromType”)]

2.1.14、#[serde(into = “IntoType”)]

2.1.15、#[serde(crate = “…”)]

2.1.16、#[serde(expecting = “…”)]

2.2、变量属性

2.2.1、#[serde(rename = “name”)]

2.2.2、#[serde(alias = “name”)]

2.2.3、#[serde(rename_all = “…”)]

2.2.4、#[serde(skip)]

2.2.5、#[serde(skip_serializing)]

2.2.6、#[serde(skip_deserializing)]

2.2.7、#[serde(serialize_with = “path”)]

2.2.8、#[serde(deserialize_with = “path”)]

2.2.9、#[serde(with = “module”)]

2.2.10、#[serde(bound = “T: MyTrait”)]

2.2.11、#[serde(borrow)] and #[serde(borrow = “'a + 'b + …”)]

2.2.12、#[serde(other)]

2.3、自段属性

2.3.1、#[serde(rename = “name”)]

2.3.2、#[serde(alias = “name”)]

2.3.3、#[serde(default)]

2.3.4、#[serde(default = “path”)]

2.3.5、#[serde(flatten)]

2.3.6、#[serde(skip)]

2.3.7、#[serde(skip_serializing)]

2.3.8、#[serde(skip_deserializing)]

2.3.9、#[serde(skip_serializing_if = “path”)]

2.3.10、#[serde(serialize_with = “path”)]

2.3.11、#[serde(deserialize_with = “path”)]

2.3.12、#[serde(with = “module”)]

2.3.13、#[serde(borrow)] and #[serde(borrow = “'a + 'b + …”)]

2.3.14、#[serde(bound = “T: MyTrait”)]

2.3.3、#[serde(getter = “…”)]

三、自定义序列化

3.1、实现序列化

3.1.1、Serialize

序列化接口定义

pub trait Serialize {fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>whereS: Serializer;
}

3.1.2、原始类型

示例:

impl Serialize for i32 {fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>whereS: Serializer,{serializer.serialize_i32(*self)}
}

3.1.3、序列化结构体

use serde::ser::{Serialize, Serializer, SerializeStruct};struct Color {r: u8,g: u8,b: u8,
}impl Serialize for Color {fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>whereS: 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()}

3.2、实现反序列化

3.2.1、反序列化 trait

pub trait Deserialize<'de>: Sized {fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>whereD: Deserializer<'de>;
}

3.2.2、Visitor trait

访问器是由反序列化实现实例化并且传递给反序列化器

3.3、单元测试

use linked_hash_map::LinkedHashMap;
use serde_test::{Token, assert_tokens};#[test]
fn test_ser_de_empty() {let map = LinkedHashMap::<char, u32>::new();assert_tokens(&map, &[Token::Map { len: Some(0) },Token::MapEnd,]);
}#[test]
fn test_ser_de() {let mut map = LinkedHashMap::new();map.insert('b', 20);map.insert('a', 10);map.insert('c', 30);assert_tokens(&map, &[Token::Map { len: Some(3) },Token::Char('b'),Token::I32(20),Token::Char('a'),Token::I32(10),Token::Char('c'),Token::I32(30),Token::MapEnd,]);
}

四、写一个数据格式

4.1、约定

  • Error 是序列化和反序列化共同的错误类型
  • Result 类型的定义:等价于 std:: Result::Result
  • 序列化类型:实现 serde::Serializer 的序列化器类型
  • 反序列化类型:实现 serde::Deserializer 的反序列化类型
  • 一个或多个函数 具体取决于格式支持序列化到的类型
  • 一个或多个函数具体取决于格式支持反序列化的类型

4.2、错误处理

在序列化过程中,Serialize 将 Rust 数据结构映射到 Serde 到数据模型中。在反序列化期间,反序列化器将输入数据映射到 Serde 数据模型中,反序列化和访问器 trait 将数据模型映射到数据接结构中,这些步骤都可能失败

  • 序列化可能失败
  • 序列化器可能失败
  • 反序列化器可能失败
  • 反学序列化可能失败
use std;
use std::fmt::{self, Display};use serde::{de, ser};pub type Result<T> = std::result::Result<T, Error>;// This is a bare-bones implementation. A real library would provide additional
// information in its error type, for example the line and column at which the
// error occurred, the byte offset into the input, or the current key being
// processed.
#[derive(Debug)]
pub enum Error {// One or more variants that can be created by data structures through the// `ser::Error` and `de::Error` traits. For example the Serialize impl for// Mutex<T> might return an error because the mutex is poisoned, or the// Deserialize impl for a struct may return an error because a required// field is missing.Message(String),// Zero or more variants that can be created directly by the Serializer and// Deserializer without going through `ser::Error` and `de::Error`. These// are specific to the format, in this case JSON.Eof,Syntax,ExpectedBoolean,ExpectedInteger,ExpectedString,ExpectedNull,ExpectedArray,ExpectedArrayComma,ExpectedArrayEnd,ExpectedMap,ExpectedMapColon,ExpectedMapComma,ExpectedMapEnd,ExpectedEnum,TrailingCharacters,
}impl ser::Error for Error {fn custom<T: Display>(msg: T) -> Self {Error::Message(msg.to_string())}
}impl de::Error for Error {fn custom<T: Display>(msg: T) -> Self {Error::Message(msg.to_string())}
}impl Display for Error {fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {match self {Error::Message(msg) => formatter.write_str(msg),Error::Eof => formatter.write_str("unexpected end of input"),/* and so forth */}}
}impl std::error::Error for Error {}

4.3、实现序列化

use serde::{ser, Serialize};use error::{Error, Result};pub struct Serializer {// This string starts empty and JSON is appended as values are serialized.output: String,
}// By convention, the public API of a Serde serializer is one or more `to_abc`
// functions such as `to_string`, `to_bytes`, or `to_writer` depending on what
// Rust types the serializer is able to produce as output.
//
// This basic serializer supports only `to_string`.
pub fn to_string<T>(value: &T) -> Result<String>
whereT: Serialize,
{let mut serializer = Serializer {output: String::new(),};value.serialize(&mut serializer)?;Ok(serializer.output)
}impl<'a> ser::Serializer for &'a mut Serializer {// The output type produced by this `Serializer` during successful// serialization. Most serializers that produce text or binary output should// set `Ok = ()` and serialize into an `io::Write` or buffer contained// within the `Serializer` instance, as happens here. Serializers that build// in-memory data structures may be simplified by using `Ok` to propagate// the data structure around.type Ok = ();// The error type when some error occurs during serialization.type Error = Error;// Associated types for keeping track of additional state while serializing// compound data structures like sequences and maps. In this case no// additional state is required beyond what is already stored in the// Serializer struct.type SerializeSeq = Self;type SerializeTuple = Self;type SerializeTupleStruct = Self;type SerializeTupleVariant = Self;type SerializeMap = Self;type SerializeStruct = Self;type SerializeStructVariant = Self;// Here we go with the simple methods. The following 12 methods receive one// of the primitive types of the data model and map it to JSON by appending// into the output string.fn serialize_bool(self, v: bool) -> Result<()> {self.output += if v { "true" } else { "false" };Ok(())}// JSON does not distinguish between different sizes of integers, so all// signed integers will be serialized the same and all unsigned integers// will be serialized the same. Other formats, especially compact binary// formats, may need independent logic for the different sizes.fn serialize_i8(self, v: i8) -> Result<()> {self.serialize_i64(i64::from(v))}fn serialize_i16(self, v: i16) -> Result<()> {self.serialize_i64(i64::from(v))}fn serialize_i32(self, v: i32) -> Result<()> {self.serialize_i64(i64::from(v))}// Not particularly efficient but this is example code anyway. A more// performant approach would be to use the `itoa` crate.fn serialize_i64(self, v: i64) -> Result<()> {self.output += &v.to_string();Ok(())}fn serialize_u8(self, v: u8) -> Result<()> {self.serialize_u64(u64::from(v))}fn serialize_u16(self, v: u16) -> Result<()> {self.serialize_u64(u64::from(v))}fn serialize_u32(self, v: u32) -> Result<()> {self.serialize_u64(u64::from(v))}fn serialize_u64(self, v: u64) -> Result<()> {self.output += &v.to_string();Ok(())}fn serialize_f32(self, v: f32) -> Result<()> {self.serialize_f64(f64::from(v))}fn serialize_f64(self, v: f64) -> Result<()> {self.output += &v.to_string();Ok(())}// Serialize a char as a single-character string. Other formats may// represent this differently.fn serialize_char(self, v: char) -> Result<()> {self.serialize_str(&v.to_string())}// This only works for strings that don't require escape sequences but you// get the idea. For example it would emit invalid JSON if the input string// contains a '"' character.fn serialize_str(self, v: &str) -> Result<()> {self.output += "\"";self.output += v;self.output += "\"";Ok(())}// Serialize a byte array as an array of bytes. Could also use a base64// string here. Binary formats will typically represent byte arrays more// compactly.fn serialize_bytes(self, v: &[u8]) -> Result<()> {use serde::ser::SerializeSeq;let mut seq = self.serialize_seq(Some(v.len()))?;for byte in v {seq.serialize_element(byte)?;}seq.end()}// An absent optional is represented as the JSON `null`.fn serialize_none(self) -> Result<()> {self.serialize_unit()}// A present optional is represented as just the contained value. Note that// this is a lossy representation. For example the values `Some(())` and// `None` both serialize as just `null`. Unfortunately this is typically// what people expect when working with JSON. Other formats are encouraged// to behave more intelligently if possible.fn serialize_some<T>(self, value: &T) -> Result<()>whereT: ?Sized + Serialize,{value.serialize(self)}// In Serde, unit means an anonymous value containing no data. Map this to// JSON as `null`.fn serialize_unit(self) -> Result<()> {self.output += "null";Ok(())}// Unit struct means a named value containing no data. Again, since there is// no data, map this to JSON as `null`. There is no need to serialize the// name in most formats.fn serialize_unit_struct(self, _name: &'static str) -> Result<()> {self.serialize_unit()}// When serializing a unit variant (or any other kind of variant), formats// can choose whether to keep track of it by index or by name. Binary// formats typically use the index of the variant and human-readable formats// typically use the name.fn serialize_unit_variant(self,_name: &'static str,_variant_index: u32,variant: &'static str,) -> Result<()> {self.serialize_str(variant)}// As is done here, serializers are encouraged to treat newtype structs as// insignificant wrappers around the data they contain.fn serialize_newtype_struct<T>(self,_name: &'static str,value: &T,) -> Result<()>whereT: ?Sized + Serialize,{value.serialize(self)}// Note that newtype variant (and all of the other variant serialization// methods) refer exclusively to the "externally tagged" enum// representation.//// Serialize this to JSON in externally tagged form as `{ NAME: VALUE }`.fn serialize_newtype_variant<T>(self,_name: &'static str,_variant_index: u32,variant: &'static str,value: &T,) -> Result<()>whereT: ?Sized + Serialize,{self.output += "{";variant.serialize(&mut *self)?;self.output += ":";value.serialize(&mut *self)?;self.output += "}";Ok(())}// Now we get to the serialization of compound types.//// The start of the sequence, each value, and the end are three separate// method calls. This one is responsible only for serializing the start,// which in JSON is `[`.//// The length of the sequence may or may not be known ahead of time. This// doesn't make a difference in JSON because the length is not represented// explicitly in the serialized form. Some serializers may only be able to// support sequences for which the length is known up front.fn serialize_seq(self, _len: Option<usize>) -> Result<Self::SerializeSeq> {self.output += "[";Ok(self)}// Tuples look just like sequences in JSON. Some formats may be able to// represent tuples more efficiently by omitting the length, since tuple// means that the corresponding `Deserialize implementation will know the// length without needing to look at the serialized data.fn serialize_tuple(self, len: usize) -> Result<Self::SerializeTuple> {self.serialize_seq(Some(len))}// Tuple structs look just like sequences in JSON.fn serialize_tuple_struct(self,_name: &'static str,len: usize,) -> Result<Self::SerializeTupleStruct> {self.serialize_seq(Some(len))}// Tuple variants are represented in JSON as `{ NAME: [DATA...] }`. Again// this method is only responsible for the externally tagged representation.fn serialize_tuple_variant(self,_name: &'static str,_variant_index: u32,variant: &'static str,_len: usize,) -> Result<Self::SerializeTupleVariant> {self.output += "{";variant.serialize(&mut *self)?;self.output += ":[";Ok(self)}// Maps are represented in JSON as `{ K: V, K: V, ... }`.fn serialize_map(self, _len: Option<usize>) -> Result<Self::SerializeMap> {self.output += "{";Ok(self)}// Structs look just like maps in JSON. In particular, JSON requires that we// serialize the field names of the struct. Other formats may be able to// omit the field names when serializing structs because the corresponding// Deserialize implementation is required to know what the keys are without// looking at the serialized data.fn serialize_struct(self,_name: &'static str,len: usize,) -> Result<Self::SerializeStruct> {self.serialize_map(Some(len))}// Struct variants are represented in JSON as `{ NAME: { K: V, ... } }`.// This is the externally tagged representation.fn serialize_struct_variant(self,_name: &'static str,_variant_index: u32,variant: &'static str,_len: usize,) -> Result<Self::SerializeStructVariant> {self.output += "{";variant.serialize(&mut *self)?;self.output += ":{";Ok(self)}
}// The following 7 impls deal with the serialization of compound types like
// sequences and maps. Serialization of such types is begun by a Serializer
// method and followed by zero or more calls to serialize individual elements of
// the compound type and one call to end the compound type.
//
// This impl is SerializeSeq so these methods are called after `serialize_seq`
// is called on the Serializer.
impl<'a> ser::SerializeSeq for &'a mut Serializer {// Must match the `Ok` type of the serializer.type Ok = ();// Must match the `Error` type of the serializer.type Error = Error;// Serialize a single element of the sequence.fn serialize_element<T>(&mut self, value: &T) -> Result<()>whereT: ?Sized + Serialize,{if !self.output.ends_with('[') {self.output += ",";}value.serialize(&mut **self)}// Close the sequence.fn end(self) -> Result<()> {self.output += "]";Ok(())}
}// Same thing but for tuples.
impl<'a> ser::SerializeTuple for &'a mut Serializer {type Ok = ();type Error = Error;fn serialize_element<T>(&mut self, value: &T) -> Result<()>whereT: ?Sized + Serialize,{if !self.output.ends_with('[') {self.output += ",";}value.serialize(&mut **self)}fn end(self) -> Result<()> {self.output += "]";Ok(())}
}// Same thing but for tuple structs.
impl<'a> ser::SerializeTupleStruct for &'a mut Serializer {type Ok = ();type Error = Error;fn serialize_field<T>(&mut self, value: &T) -> Result<()>whereT: ?Sized + Serialize,{if !self.output.ends_with('[') {self.output += ",";}value.serialize(&mut **self)}fn end(self) -> Result<()> {self.output += "]";Ok(())}
}// Tuple variants are a little different. Refer back to the
// `serialize_tuple_variant` method above:
//
//    self.output += "{";
//    variant.serialize(&mut *self)?;
//    self.output += ":[";
//
// So the `end` method in this impl is responsible for closing both the `]` and
// the `}`.
impl<'a> ser::SerializeTupleVariant for &'a mut Serializer {type Ok = ();type Error = Error;fn serialize_field<T>(&mut self, value: &T) -> Result<()>whereT: ?Sized + Serialize,{if !self.output.ends_with('[') {self.output += ",";}value.serialize(&mut **self)}fn end(self) -> Result<()> {self.output += "]}";Ok(())}
}// Some `Serialize` types are not able to hold a key and value in memory at the
// same time so `SerializeMap` implementations are required to support
// `serialize_key` and `serialize_value` individually.
//
// There is a third optional method on the `SerializeMap` trait. The
// `serialize_entry` method allows serializers to optimize for the case where
// key and value are both available simultaneously. In JSON it doesn't make a
// difference so the default behavior for `serialize_entry` is fine.
impl<'a> ser::SerializeMap for &'a mut Serializer {type Ok = ();type Error = Error;// The Serde data model allows map keys to be any serializable type. JSON// only allows string keys so the implementation below will produce invalid// JSON if the key serializes as something other than a string.//// A real JSON serializer would need to validate that map keys are strings.// This can be done by using a different Serializer to serialize the key// (instead of `&mut **self`) and having that other serializer only// implement `serialize_str` and return an error on any other data type.fn serialize_key<T>(&mut self, key: &T) -> Result<()>whereT: ?Sized + Serialize,{if !self.output.ends_with('{') {self.output += ",";}key.serialize(&mut **self)}// It doesn't make a difference whether the colon is printed at the end of// `serialize_key` or at the beginning of `serialize_value`. In this case// the code is a bit simpler having it here.fn serialize_value<T>(&mut self, value: &T) -> Result<()>whereT: ?Sized + Serialize,{self.output += ":";value.serialize(&mut **self)}fn end(self) -> Result<()> {self.output += "}";Ok(())}
}// Structs are like maps in which the keys are constrained to be compile-time
// constant strings.
impl<'a> ser::SerializeStruct for &'a mut Serializer {type Ok = ();type Error = Error;fn serialize_field<T>(&mut self, key: &'static str, value: &T) -> Result<()>whereT: ?Sized + Serialize,{if !self.output.ends_with('{') {self.output += ",";}key.serialize(&mut **self)?;self.output += ":";value.serialize(&mut **self)}fn end(self) -> Result<()> {self.output += "}";Ok(())}
}// Similar to `SerializeTupleVariant`, here the `end` method is responsible for
// closing both of the curly braces opened by `serialize_struct_variant`.
impl<'a> ser::SerializeStructVariant for &'a mut Serializer {type Ok = ();type Error = Error;fn serialize_field<T>(&mut self, key: &'static str, value: &T) -> Result<()>whereT: ?Sized + Serialize,{if !self.output.ends_with('{') {self.output += ",";}key.serialize(&mut **self)?;self.output += ":";value.serialize(&mut **self)}fn end(self) -> Result<()> {self.output += "}}";Ok(())}
}#[test]
fn test_struct() {#[derive(Serialize)]struct Test {int: u32,seq: Vec<&'static str>,}let test = Test {int: 1,seq: vec!["a", "b"],};let expected = r#"{"int":1,"seq":["a","b"]}"#;assert_eq!(to_string(&test).unwrap(), expected);
}#[test]
fn test_enum() {#[derive(Serialize)]enum E {Unit,Newtype(u32),Tuple(u32, u32),Struct { a: u32 },}let u = E::Unit;let expected = r#""Unit""#;assert_eq!(to_string(&u).unwrap(), expected);let n = E::Newtype(1);let expected = r#"{"Newtype":1}"#;assert_eq!(to_string(&n).unwrap(), expected);let t = E::Tuple(1, 2);let expected = r#"{"Tuple":[1,2]}"#;assert_eq!(to_string(&t).unwrap(), expected);let s = E::Struct { a: 1 };let expected = r#"{"Struct":{"a":1}}"#;assert_eq!(to_string(&s).unwrap(), expected);
}

4.3、实现反序列化

use std::ops::{AddAssign, MulAssign, Neg};use serde::Deserialize;
use serde::de::{self, DeserializeSeed, EnumAccess, IntoDeserializer, MapAccess, SeqAccess,VariantAccess, Visitor,
};use error::{Error, Result};pub struct Deserializer<'de> {// This string starts with the input data and characters are truncated off// the beginning as data is parsed.input: &'de str,
}impl<'de> Deserializer<'de> {// By convention, `Deserializer` constructors are named like `from_xyz`.// That way basic use cases are satisfied by something like// `serde_json::from_str(...)` while advanced use cases that require a// deserializer can make one with `serde_json::Deserializer::from_str(...)`.pub fn from_str(input: &'de str) -> Self {Deserializer { input }}
}// By convention, the public API of a Serde deserializer is one or more
// `from_xyz` methods such as `from_str`, `from_bytes`, or `from_reader`
// depending on what Rust types the deserializer is able to consume as input.
//
// This basic deserializer supports only `from_str`.
pub fn from_str<'a, T>(s: &'a str) -> Result<T>
whereT: Deserialize<'a>,
{let mut deserializer = Deserializer::from_str(s);let t = T::deserialize(&mut deserializer)?;if deserializer.input.is_empty() {Ok(t)} else {Err(Error::TrailingCharacters)}
}// SERDE IS NOT A PARSING LIBRARY. This impl block defines a few basic parsing
// functions from scratch. More complicated formats may wish to use a dedicated
// parsing library to help implement their Serde deserializer.
impl<'de> Deserializer<'de> {// Look at the first character in the input without consuming it.fn peek_char(&mut self) -> Result<char> {self.input.chars().next().ok_or(Error::Eof)}// Consume the first character in the input.fn next_char(&mut self) -> Result<char> {let ch = self.peek_char()?;self.input = &self.input[ch.len_utf8()..];Ok(ch)}// Parse the JSON identifier `true` or `false`.fn parse_bool(&mut self) -> Result<bool> {if self.input.starts_with("true") {self.input = &self.input["true".len()..];Ok(true)} else if self.input.starts_with("false") {self.input = &self.input["false".len()..];Ok(false)} else {Err(Error::ExpectedBoolean)}}// Parse a group of decimal digits as an unsigned integer of type T.//// This implementation is a bit too lenient, for example `001` is not// allowed in JSON. Also the various arithmetic operations can overflow and// panic or return bogus data. But it is good enough for example code!fn parse_unsigned<T>(&mut self) -> Result<T>whereT: AddAssign<T> + MulAssign<T> + From<u8>,{let mut int = match self.next_char()? {ch @ '0'..='9' => T::from(ch as u8 - b'0'),_ => {return Err(Error::ExpectedInteger);}};loop {match self.input.chars().next() {Some(ch @ '0'..='9') => {self.input = &self.input[1..];int *= T::from(10);int += T::from(ch as u8 - b'0');}_ => {return Ok(int);}}}}// Parse a possible minus sign followed by a group of decimal digits as a// signed integer of type T.fn parse_signed<T>(&mut self) -> Result<T>whereT: Neg<Output = T> + AddAssign<T> + MulAssign<T> + From<i8>,{// Optional minus sign, delegate to `parse_unsigned`, negate if negative.unimplemented!()}// Parse a string until the next '"' character.//// Makes no attempt to handle escape sequences. What did you expect? This is// example code!fn parse_string(&mut self) -> Result<&'de str> {if self.next_char()? != '"' {return Err(Error::ExpectedString);}match self.input.find('"') {Some(len) => {let s = &self.input[..len];self.input = &self.input[len + 1..];Ok(s)}None => Err(Error::Eof),}}
}impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {type Error = Error;// Look at the input data to decide what Serde data model type to// deserialize as. Not all data formats are able to support this operation.// Formats that support `deserialize_any` are known as self-describing.fn deserialize_any<V>(self, visitor: V) -> Result<V::Value>whereV: Visitor<'de>,{match self.peek_char()? {'n' => self.deserialize_unit(visitor),'t' | 'f' => self.deserialize_bool(visitor),'"' => self.deserialize_str(visitor),'0'..='9' => self.deserialize_u64(visitor),'-' => self.deserialize_i64(visitor),'[' => self.deserialize_seq(visitor),'{' => self.deserialize_map(visitor),_ => Err(Error::Syntax),}}// Uses the `parse_bool` parsing function defined above to read the JSON// identifier `true` or `false` from the input.//// Parsing refers to looking at the input and deciding that it contains the// JSON value `true` or `false`.//// Deserialization refers to mapping that JSON value into Serde's data// model by invoking one of the `Visitor` methods. In the case of JSON and// bool that mapping is straightforward so the distinction may seem silly,// but in other cases Deserializers sometimes perform non-obvious mappings.// For example the TOML format has a Datetime type and Serde's data model// does not. In the `toml` crate, a Datetime in the input is deserialized by// mapping it to a Serde data model "struct" type with a special name and a// single field containing the Datetime represented as a string.fn deserialize_bool<V>(self, visitor: V) -> Result<V::Value>whereV: Visitor<'de>,{visitor.visit_bool(self.parse_bool()?)}// The `parse_signed` function is generic over the integer type `T` so here// it is invoked with `T=i8`. The next 8 methods are similar.fn deserialize_i8<V>(self, visitor: V) -> Result<V::Value>whereV: Visitor<'de>,{visitor.visit_i8(self.parse_signed()?)}fn deserialize_i16<V>(self, visitor: V) -> Result<V::Value>whereV: Visitor<'de>,{visitor.visit_i16(self.parse_signed()?)}fn deserialize_i32<V>(self, visitor: V) -> Result<V::Value>whereV: Visitor<'de>,{visitor.visit_i32(self.parse_signed()?)}fn deserialize_i64<V>(self, visitor: V) -> Result<V::Value>whereV: Visitor<'de>,{visitor.visit_i64(self.parse_signed()?)}fn deserialize_u8<V>(self, visitor: V) -> Result<V::Value>whereV: Visitor<'de>,{visitor.visit_u8(self.parse_unsigned()?)}fn deserialize_u16<V>(self, visitor: V) -> Result<V::Value>whereV: Visitor<'de>,{visitor.visit_u16(self.parse_unsigned()?)}fn deserialize_u32<V>(self, visitor: V) -> Result<V::Value>whereV: Visitor<'de>,{visitor.visit_u32(self.parse_unsigned()?)}fn deserialize_u64<V>(self, visitor: V) -> Result<V::Value>whereV: Visitor<'de>,{visitor.visit_u64(self.parse_unsigned()?)}// Float parsing is stupidly hard.fn deserialize_f32<V>(self, _visitor: V) -> Result<V::Value>whereV: Visitor<'de>,{unimplemented!()}// Float parsing is stupidly hard.fn deserialize_f64<V>(self, _visitor: V) -> Result<V::Value>whereV: Visitor<'de>,{unimplemented!()}// The `Serializer` implementation on the previous page serialized chars as// single-character strings so handle that representation here.fn deserialize_char<V>(self, _visitor: V) -> Result<V::Value>whereV: Visitor<'de>,{// Parse a string, check that it is one character, call `visit_char`.unimplemented!()}// Refer to the "Understanding deserializer lifetimes" page for information// about the three deserialization flavors of strings in Serde.fn deserialize_str<V>(self, visitor: V) -> Result<V::Value>whereV: Visitor<'de>,{visitor.visit_borrowed_str(self.parse_string()?)}fn deserialize_string<V>(self, visitor: V) -> Result<V::Value>whereV: Visitor<'de>,{self.deserialize_str(visitor)}// The `Serializer` implementation on the previous page serialized byte// arrays as JSON arrays of bytes. Handle that representation here.fn deserialize_bytes<V>(self, _visitor: V) -> Result<V::Value>whereV: Visitor<'de>,{unimplemented!()}fn deserialize_byte_buf<V>(self, _visitor: V) -> Result<V::Value>whereV: Visitor<'de>,{unimplemented!()}// An absent optional is represented as the JSON `null` and a present// optional is represented as just the contained value.//// As commented in `Serializer` implementation, this is a lossy// representation. For example the values `Some(())` and `None` both// serialize as just `null`. Unfortunately this is typically what people// expect when working with JSON. Other formats are encouraged to behave// more intelligently if possible.fn deserialize_option<V>(self, visitor: V) -> Result<V::Value>whereV: Visitor<'de>,{if self.input.starts_with("null") {self.input = &self.input["null".len()..];visitor.visit_none()} else {visitor.visit_some(self)}}// In Serde, unit means an anonymous value containing no data.fn deserialize_unit<V>(self, visitor: V) -> Result<V::Value>whereV: Visitor<'de>,{if self.input.starts_with("null") {self.input = &self.input["null".len()..];visitor.visit_unit()} else {Err(Error::ExpectedNull)}}// Unit struct means a named value containing no data.fn deserialize_unit_struct<V>(self,_name: &'static str,visitor: V,) -> Result<V::Value>whereV: Visitor<'de>,{self.deserialize_unit(visitor)}// As is done here, serializers are encouraged to treat newtype structs as// insignificant wrappers around the data they contain. That means not// parsing anything other than the contained value.fn deserialize_newtype_struct<V>(self,_name: &'static str,visitor: V,) -> Result<V::Value>whereV: Visitor<'de>,{visitor.visit_newtype_struct(self)}// Deserialization of compound types like sequences and maps happens by// passing the visitor an "Access" object that gives it the ability to// iterate through the data contained in the sequence.fn deserialize_seq<V>(self, visitor: V) -> Result<V::Value>whereV: Visitor<'de>,{// Parse the opening bracket of the sequence.if self.next_char()? == '[' {// Give the visitor access to each element of the sequence.let value = visitor.visit_seq(CommaSeparated::new(self))?;// Parse the closing bracket of the sequence.if self.next_char()? == ']' {Ok(value)} else {Err(Error::ExpectedArrayEnd)}} else {Err(Error::ExpectedArray)}}// Tuples look just like sequences in JSON. Some formats may be able to// represent tuples more efficiently.//// As indicated by the length parameter, the `Deserialize` implementation// for a tuple in the Serde data model is required to know the length of the// tuple before even looking at the input data.fn deserialize_tuple<V>(self, _len: usize, visitor: V) -> Result<V::Value>whereV: Visitor<'de>,{self.deserialize_seq(visitor)}// Tuple structs look just like sequences in JSON.fn deserialize_tuple_struct<V>(self,_name: &'static str,_len: usize,visitor: V,) -> Result<V::Value>whereV: Visitor<'de>,{self.deserialize_seq(visitor)}// Much like `deserialize_seq` but calls the visitors `visit_map` method// with a `MapAccess` implementation, rather than the visitor's `visit_seq`// method with a `SeqAccess` implementation.fn deserialize_map<V>(self, visitor: V) -> Result<V::Value>whereV: Visitor<'de>,{// Parse the opening brace of the map.if self.next_char()? == '{' {// Give the visitor access to each entry of the map.let value = visitor.visit_map(CommaSeparated::new(self))?;// Parse the closing brace of the map.if self.next_char()? == '}' {Ok(value)} else {Err(Error::ExpectedMapEnd)}} else {Err(Error::ExpectedMap)}}// Structs look just like maps in JSON.//// Notice the `fields` parameter - a "struct" in the Serde data model means// that the `Deserialize` implementation is required to know what the fields// are before even looking at the input data. Any key-value pairing in which// the fields cannot be known ahead of time is probably a map.fn deserialize_struct<V>(self,_name: &'static str,_fields: &'static [&'static str],visitor: V,) -> Result<V::Value>whereV: Visitor<'de>,{self.deserialize_map(visitor)}fn deserialize_enum<V>(self,_name: &'static str,_variants: &'static [&'static str],visitor: V,) -> Result<V::Value>whereV: Visitor<'de>,{if self.peek_char()? == '"' {// Visit a unit variant.visitor.visit_enum(self.parse_string()?.into_deserializer())} else if self.next_char()? == '{' {// Visit a newtype variant, tuple variant, or struct variant.let value = visitor.visit_enum(Enum::new(self))?;// Parse the matching close brace.if self.next_char()? == '}' {Ok(value)} else {Err(Error::ExpectedMapEnd)}} else {Err(Error::ExpectedEnum)}}// An identifier in Serde is the type that identifies a field of a struct or// the variant of an enum. In JSON, struct fields and enum variants are// represented as strings. In other formats they may be represented as// numeric indices.fn deserialize_identifier<V>(self, visitor: V) -> Result<V::Value>whereV: Visitor<'de>,{self.deserialize_str(visitor)}// Like `deserialize_any` but indicates to the `Deserializer` that it makes// no difference which `Visitor` method is called because the data is// ignored.//// Some deserializers are able to implement this more efficiently than// `deserialize_any`, for example by rapidly skipping over matched// delimiters without paying close attention to the data in between.//// Some formats are not able to implement this at all. Formats that can// implement `deserialize_any` and `deserialize_ignored_any` are known as// self-describing.fn deserialize_ignored_any<V>(self, visitor: V) -> Result<V::Value>whereV: Visitor<'de>,{self.deserialize_any(visitor)}
}// In order to handle commas correctly when deserializing a JSON array or map,
// we need to track whether we are on the first element or past the first
// element.
struct CommaSeparated<'a, 'de: 'a> {de: &'a mut Deserializer<'de>,first: bool,
}impl<'a, 'de> CommaSeparated<'a, 'de> {fn new(de: &'a mut Deserializer<'de>) -> Self {CommaSeparated {de,first: true,}}
}// `SeqAccess` is provided to the `Visitor` to give it the ability to iterate
// through elements of the sequence.
impl<'de, 'a> SeqAccess<'de> for CommaSeparated<'a, 'de> {type Error = Error;fn next_element_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>>whereT: DeserializeSeed<'de>,{// Check if there are no more elements.if self.de.peek_char()? == ']' {return Ok(None);}// Comma is required before every element except the first.if !self.first && self.de.next_char()? != ',' {return Err(Error::ExpectedArrayComma);}self.first = false;// Deserialize an array element.seed.deserialize(&mut *self.de).map(Some)}
}// `MapAccess` is provided to the `Visitor` to give it the ability to iterate
// through entries of the map.
impl<'de, 'a> MapAccess<'de> for CommaSeparated<'a, 'de> {type Error = Error;fn next_key_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>>whereK: DeserializeSeed<'de>,{// Check if there are no more entries.if self.de.peek_char()? == '}' {return Ok(None);}// Comma is required before every entry except the first.if !self.first && self.de.next_char()? != ',' {return Err(Error::ExpectedMapComma);}self.first = false;// Deserialize a map key.seed.deserialize(&mut *self.de).map(Some)}fn next_value_seed<V>(&mut self, seed: V) -> Result<V::Value>whereV: DeserializeSeed<'de>,{// It doesn't make a difference whether the colon is parsed at the end// of `next_key_seed` or at the beginning of `next_value_seed`. In this// case the code is a bit simpler having it here.if self.de.next_char()? != ':' {return Err(Error::ExpectedMapColon);}// Deserialize a map value.seed.deserialize(&mut *self.de)}
}struct Enum<'a, 'de: 'a> {de: &'a mut Deserializer<'de>,
}impl<'a, 'de> Enum<'a, 'de> {fn new(de: &'a mut Deserializer<'de>) -> Self {Enum { de }}
}// `EnumAccess` is provided to the `Visitor` to give it the ability to determine
// which variant of the enum is supposed to be deserialized.
//
// Note that all enum deserialization methods in Serde refer exclusively to the
// "externally tagged" enum representation.
impl<'de, 'a> EnumAccess<'de> for Enum<'a, 'de> {type Error = Error;type Variant = Self;fn variant_seed<V>(self, seed: V) -> Result<(V::Value, Self::Variant)>whereV: DeserializeSeed<'de>,{// The `deserialize_enum` method parsed a `{` character so we are// currently inside of a map. The seed will be deserializing itself from// the key of the map.let val = seed.deserialize(&mut *self.de)?;// Parse the colon separating map key from value.if self.de.next_char()? == ':' {Ok((val, self))} else {Err(Error::ExpectedMapColon)}}
}// `VariantAccess` is provided to the `Visitor` to give it the ability to see
// the content of the single variant that it decided to deserialize.
impl<'de, 'a> VariantAccess<'de> for Enum<'a, 'de> {type Error = Error;// If the `Visitor` expected this variant to be a unit variant, the input// should have been the plain string case handled in `deserialize_enum`.fn unit_variant(self) -> Result<()> {Err(Error::ExpectedString)}// Newtype variants are represented in JSON as `{ NAME: VALUE }` so// deserialize the value here.fn newtype_variant_seed<T>(self, seed: T) -> Result<T::Value>whereT: DeserializeSeed<'de>,{seed.deserialize(self.de)}// Tuple variants are represented in JSON as `{ NAME: [DATA...] }` so// deserialize the sequence of data here.fn tuple_variant<V>(self, _len: usize, visitor: V) -> Result<V::Value>whereV: Visitor<'de>,{de::Deserializer::deserialize_seq(self.de, visitor)}// Struct variants are represented in JSON as `{ NAME: { K: V, ... } }` so// deserialize the inner map here.fn struct_variant<V>(self,_fields: &'static [&'static str],visitor: V,) -> Result<V::Value>whereV: Visitor<'de>,{de::Deserializer::deserialize_map(self.de, visitor)}
}#[test]
fn test_struct() {#[derive(Deserialize, PartialEq, Debug)]struct Test {int: u32,seq: Vec<String>,}let j = r#"{"int":1,"seq":["a","b"]}"#;let expected = Test {int: 1,seq: vec!["a".to_owned(), "b".to_owned()],};assert_eq!(expected, from_str(j).unwrap());
}#[test]
fn test_enum() {#[derive(Deserialize, PartialEq, Debug)]enum E {Unit,Newtype(u32),Tuple(u32, u32),Struct { a: u32 },}let j = r#""Unit""#;let expected = E::Unit;assert_eq!(expected, from_str(j).unwrap());let j = r#"{"Newtype":1}"#;let expected = E::Newtype(1);assert_eq!(expected, from_str(j).unwrap());let j = r#"{"Tuple":[1,2]}"#;let expected = E::Tuple(1, 2);assert_eq!(expected, from_str(j).unwrap());let j = r#"{"Struct":{"a":1}}"#;let expected = E::Struct { a: 1 };assert_eq!(expected, from_str(j).unwrap());
}

五、反序列化生命周期

5.1、理解反序列化生命周期

Deserialize 和 Deserializer 拥有一个生命周期:'de

trait Deserialize<'de>: Sized {fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>whereD: Deserializer<'de>;
}

生命周期能够安全地跨各种数据执行有效的零拷贝反序列化,在 Rust 以外的语言中是不可能的或不安全的。

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

零拷贝反序列化意味着反序列化到一个数据结构中,保存输入的字符串或字节数组中借用字符串或字节数组数据。

避免为每个单独的字段分配内存来存储字符串,然后将字符串数据从输入复制到新分配的字段

5.2、trait 边界

包含有两种 trait 边界

  • <'de, T> where T: Deserialize<'de> :这意味着调用者可以决定它的生命周期
  • where T: DeserializeOwned:被调用者可以决定什么生命周期,意味着可以从任何生命周期反序列化。

5.3、暂态(Transient)、借用(borrowed)和拥有的数据(owned data)

5.3.1、暂态(Transient)

visit_str 接受一个 &str

5.3.2、借用(Borrowed)

visit_borrowed_str accepts 接收一个 &'de str

5.3.3、拥有(Owned)

visit_string 接收一个 String。

相关文章:

【跟小嘉学 Rust 编程】二十六、Rust的序列化解决方案(Serde)

系列文章目录 【跟小嘉学 Rust 编程】一、Rust 编程基础 【跟小嘉学 Rust 编程】二、Rust 包管理工具使用 【跟小嘉学 Rust 编程】三、Rust 的基本程序概念 【跟小嘉学 Rust 编程】四、理解 Rust 的所有权概念 【跟小嘉学 Rust 编程】五、使用结构体关联结构化数据 【跟小嘉学…...

菜鸟教程《Python 3 教程》笔记(14):函数

菜鸟教程《Python 3 教程》笔记&#xff08;14&#xff09; 14 函数14.1 参数传递14.1.1 可更改(mutable)与不可更改(immutable)对象14.1.2 python 传不可变对象实例 14.2 参数14.2.1 必需参数14.2.2 关键字参数14.2.3 默认参数14.2.4 不定长参数 14.3 匿名函数14.4 强制位置参…...

SEC推迟ETF,BTC跌破26k,十年之约#6逢跌加仓

今日荐读&#xff1a;8.31教链内参《美证监会推迟所有的BTC现货ETF申请》。刘教链Pro《BTC的流速》。 * * * 刘教链 原创 * * * 原本是9.2的截止日&#xff0c;美SEC昨晚就忙不迭地放出了话&#xff0c;所有现货比特币ETF的申请&#xff0c;推迟&#xff0c;统统推迟。不管你什…...

c++20 多线程并发 latch barrier semaphore

背景: c20 关于多线程并发新增了 latch, barrier, semaphore ,接下来就按照一个一个进行介绍 latch latch 是一次性使用的线程协调点, 一旦给定数量的线程达到latch点时, 所有线程都会解除阻塞, 并继续执行. 基本上它是一个计数器, 在每个线程到达latch点时倒数, 一旦计数器达…...

【8 排序】简单选择排序。

顺序表&#xff1a; void Swap(int &a,int &b){int temp;tempa;ab;btemp; } void SelectSort(int A[],int n){int min,i,j;for(i0;i<n-1;i){mini;for(ji1;j<n;j)if(A[j]<A[min])minj;if(min!i)Swap(A[i],A[min]);} } 单链表&#xff1a; void SelectSort…...

中国太保首席数据库专家林春:先难后易,核心系统数据库升级复盘

P17 是中国太平洋保险&#xff08;以下简称太保&#xff09;关联关系最为复杂、商业数据库绑定程度最深、业务影响最多的核心系统之一。但就是这样一个对太保业务至关重要的系统却被选为数据库升级的“实验品”。当然&#xff0c;说是“实验品”只是因为这是太保第一次对关键的…...

数字孪生智慧工厂:电缆厂 3D 可视化管控系统

近年来&#xff0c;我国各类器材制造业已经开始向数字化生产转型&#xff0c;使得生产流程变得更加精准高效。通过应用智能设备、物联网和大数据分析等技术&#xff0c;企业可以更好地监控生产线上的运行和质量情况&#xff0c;及时发现和解决问题&#xff0c;从而提高生产效率…...

使用WebSocket实现聊天功能

提示&#xff1a;写完文章后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、数据库设计二、实现代码1.SessionWrap2.websocket3.insertMessage4.清除未读 前言 使用WebSocket实现一对一的聊天功能与未读消息功能 一、数据库设计 会话…...

Ubuntu升级Cmake、gcc、g++

背景 最近要安装llvm&#xff0c;我选择的是从源码安装&#xff0c;所以要使用Cmake进行构建项目。但是服务器上的Cmake、gcc、g的版本都太低了&#xff0c;不符合要求&#xff0c;所以要对此进行升级。在本博客中采用的升级方法不一定是最好的方法&#xff08;因为我也是参考…...

8月28日上课内容 第四章 MySQL备份与恢复

本章结构 前言&#xff1a;日志⭐⭐ MySQL 的日志默认保存位置为 /usr/local/mysql/data ##配置文件 vim /etc/my.cnf [mysqld] ##错误日志&#xff0c;用来记录当MySQL启动、停止或运行时发生的错误信息&#xff0c;默认已开启 log-error/usr/local/mysql/data/mysql_error.l…...

es字段查询加keyword和不加keyword的区别

在ES&#xff08;Elasticsearch&#xff09;中&#xff0c;查询字段名后面加上"keyword"和不加"keyword"有着不同的含义和用途。 当字段名后面加上"keyword"时&#xff0c;表示该字段是一个keyword类型的字段。Keyword类型的字段会将文本作为一…...

前端JavaScript将数据转换成JSON字符串以及将JSON字符串转换成对象的两个API

在前端 JavaScript 中&#xff0c;你可以使用 JSON.stringify() 方法将 JavaScript 数据转换成 JSON 字符串&#xff0c;以及使用 JSON.parse() 方法将 JSON 字符串转换成 JavaScript 对象。下面是这两个 API 的详细说明和示例&#xff1a; JSON.stringify()&#xff1a; 用于…...

Spring——Spring Boot基础

文章目录 第一个helloword项目新建 Spring Boot 项目Spring Boot 项目结构分析SpringBootApplication 注解分析新建一个 Controller大功告成,运行项目 简而言之&#xff0c;从本质上来说&#xff0c;Spring Boot 就是 Spring&#xff0c;它做了那些没有它你自己也会去做的 Spri…...

Python基础之基础语法(二)

Python基础之基础语法(二) 语言类型 静态语言 如&#xff1a;C C Java ina a 100 a 100 a abc # 不可以静态语言需要指定声明标识符的类型&#xff0c;之后不可以改变类型赋值。静态语言变异的时候要检查类型&#xff0c;编写源代码&#xff0c;编译时检查错误。 动态语…...

docker常见面试问题详解

在面试的时候&#xff0c;面试官常常会问一些问题&#xff1a; docker是什么&#xff0c;能做什么&#xff1f;docker和虚拟机的区别是什么呢&#xff1f;docker是用什么做隔离的&#xff1f;docke的网络类型&#xff1f;docker数据之间是如何通信的&#xff1f;docker的数据保…...

Auto-GPT 学习笔记

Auto-GPT 学习笔记 Auto-GPT 简介 Auto-GPT 是一个基于 GPT-4 的自主智能体实验项目。它展示了大规模语言模型的规划、记忆和工具使用能力。Auto-GPT 的目标是实现一个完全自主的 AI 代理。GitHub 仓库 Auto-GPT 核心模块 规划(Planning) 使用强化学习策略进行多跳思考。通…...

代码随想录 - Day30 - 修剪二叉树,转换二叉树 + 二叉树总结

代码随想录 - Day30 - 修剪二叉树&#xff0c;转换二叉树 二叉树总结 669. 修剪二叉搜索树 有点像是删除二叉搜索树的变形&#xff0c;改变了删除条件而已。 递归法&#xff1a; class Solution:def trimBST(self, root: Optional[TreeNode], low: int, high: int) -> O…...

[音视频] sdl 渲染到外部创建的窗口上

API SDL_CreateWindowFrom # 在外部窗口上创建窗口 其他 api 调用&#xff0c;按照之前的 代码 ui.setupUi(this); sdl_width ui.label->width(); sdl_height ui.label->height(); SDL_Init(SDL_INIT_VIDEO); sdl_win SDL_CreateWindowFrom((void*)ui.label->wi…...

MongoDB之索引

大数据量使用全集合查询&#xff0c;这是非常影响性能的&#xff0c;而索引可以加快查询效率&#xff0c;提高性能&#xff0c;所以这方面的知识也是必不可少的。 查询分析 explain()可以帮助我们分析查询语句性能。 语法 db.collection.find(...).explain()案例及结果 案…...

Redis的介绍

Redis的架构介绍如下: 1. 概述 Redis是一个基于内存的高性能NoSQL键值数据库,支持网络访问和持久化特性。 2. 功能架构 Redis提供字符串、哈希、列表、集合、有序集合、位数组等多种数据结构,支持事务、Lua脚本、发布订阅、流水线等功能。 3. 技术架构 Redis使用单线程的…...

19c补丁后oracle属主变化,导致不能识别磁盘组

补丁后服务器重启&#xff0c;数据库再次无法启动 ORA01017: invalid username/password; logon denied Oracle 19c 在打上 19.23 或以上补丁版本后&#xff0c;存在与用户组权限相关的问题。具体表现为&#xff0c;Oracle 实例的运行用户&#xff08;oracle&#xff09;和集…...

Qwen3-Embedding-0.6B深度解析:多语言语义检索的轻量级利器

第一章 引言&#xff1a;语义表示的新时代挑战与Qwen3的破局之路 1.1 文本嵌入的核心价值与技术演进 在人工智能领域&#xff0c;文本嵌入技术如同连接自然语言与机器理解的“神经突触”——它将人类语言转化为计算机可计算的语义向量&#xff0c;支撑着搜索引擎、推荐系统、…...

学习STC51单片机31(芯片为STC89C52RCRC)OLED显示屏1

每日一言 生活的美好&#xff0c;总是藏在那些你咬牙坚持的日子里。 硬件&#xff1a;OLED 以后要用到OLED的时候找到这个文件 OLED的设备地址 SSD1306"SSD" 是品牌缩写&#xff0c;"1306" 是产品编号。 驱动 OLED 屏幕的 IIC 总线数据传输格式 示意图 …...

【git】把本地更改提交远程新分支feature_g

创建并切换新分支 git checkout -b feature_g 添加并提交更改 git add . git commit -m “实现图片上传功能” 推送到远程 git push -u origin feature_g...

土地利用/土地覆盖遥感解译与基于CLUE模型未来变化情景预测;从基础到高级,涵盖ArcGIS数据处理、ENVI遥感解译与CLUE模型情景模拟等

&#x1f50d; 土地利用/土地覆盖数据是生态、环境和气象等诸多领域模型的关键输入参数。通过遥感影像解译技术&#xff0c;可以精准获取历史或当前任何一个区域的土地利用/土地覆盖情况。这些数据不仅能够用于评估区域生态环境的变化趋势&#xff0c;还能有效评价重大生态工程…...

EtherNet/IP转DeviceNet协议网关详解

一&#xff0c;设备主要功能 疆鸿智能JH-DVN-EIP本产品是自主研发的一款EtherNet/IP从站功能的通讯网关。该产品主要功能是连接DeviceNet总线和EtherNet/IP网络&#xff0c;本网关连接到EtherNet/IP总线中做为从站使用&#xff0c;连接到DeviceNet总线中做为从站使用。 在自动…...

OpenLayers 分屏对比(地图联动)

注&#xff1a;当前使用的是 ol 5.3.0 版本&#xff0c;天地图使用的key请到天地图官网申请&#xff0c;并替换为自己的key 地图分屏对比在WebGIS开发中是很常见的功能&#xff0c;和卷帘图层不一样的是&#xff0c;分屏对比是在各个地图中添加相同或者不同的图层进行对比查看。…...

Java面试专项一-准备篇

一、企业简历筛选规则 一般企业的简历筛选流程&#xff1a;首先由HR先筛选一部分简历后&#xff0c;在将简历给到对应的项目负责人后再进行下一步的操作。 HR如何筛选简历 例如&#xff1a;Boss直聘&#xff08;招聘方平台&#xff09; 直接按照条件进行筛选 例如&#xff1a…...

Java求职者面试指南:Spring、Spring Boot、MyBatis框架与计算机基础问题解析

Java求职者面试指南&#xff1a;Spring、Spring Boot、MyBatis框架与计算机基础问题解析 一、第一轮提问&#xff08;基础概念问题&#xff09; 1. 请解释Spring框架的核心容器是什么&#xff1f;它在Spring中起到什么作用&#xff1f; Spring框架的核心容器是IoC容器&#…...

算法:模拟

1.替换所有的问号 1576. 替换所有的问号 - 力扣&#xff08;LeetCode&#xff09; ​遍历字符串​&#xff1a;通过外层循环逐一检查每个字符。​遇到 ? 时处理​&#xff1a; 内层循环遍历小写字母&#xff08;a 到 z&#xff09;。对每个字母检查是否满足&#xff1a; ​与…...