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

Go-知识泛型

Go-知识泛型

  • 1. 认识泛型
    • 1.1 不使用泛型
    • 1.2 使用泛型
  • 2. 泛型的特点
    • 2.1 函数泛化
    • 2.2 类型泛化
  • 3. 类型约束
    • 3.1 类型集合
    • 3.2 interface 类型集合
      • 3.2.1 内置interface类型集合
      • 3.2.2 自定义interface类型集合
        • 3.2.2.1 任意类型元素
        • 3.2.2.2 近似类型元素
        • 3.2.2.3 联合类型元素
      • 3.2.3 interface类型集合运算
      • 3.2.4 基于操作的类型集合
  • 4. 小例子
    • 4.1 map.Keys 获取map的全部key
    • 4.2 Set
    • 4.3 排序 Sort
  • 5. 总结

泛型是程序设计语言的一种风格或范式,允许程序员在编写代码时使用一些以后才指定的类型,在实例化时作为参数指明这些类型。
Java,C++等多种编程语言都支持泛型,Go语言从1.18版本起也开始支持泛型。

1. 认识泛型

1.1 不使用泛型

实现两个函数对map的value值进行累加,一个是int64类型的值,一个是float64类型的值

func SumInt64(m map[string]int64) int64 {var sum int64for _, v := range m {sum += v}return sum
}func SumFloat64(m map[string]float64) float64 {var sum float64for _, v := range m {sum += v}return sum
}

接着使用两个函数

func TestSum(t *testing.T) {ints := map[string]int64{"one":   234,"two":   6755,"three": 78675,}floats := map[string]float64{"one":   123.456,"two":   7865.9658,"three": 87906.865,}t.Logf("sum ints : %v , floats : %v", SumInt64(ints), SumFloat64(floats))
}

执行如下:
在这里插入图片描述

实现同样的功能,就因为处理的数据类型不一样,就需要为每种类型编写类似的重复代码。

1.2 使用泛型

泛型函数,就是吧函数的参数和返回值“泛化”,使逻辑通用。 通用并不是对所有类型都使用,所以在声明泛型函数时,需要声明适用的“参数类型”(类型约束).

func SumValue[K comparable, V int64 | float64](m map[K]V) V {var sum Vfor _, v := range m {sum += v}return sum
}

SumValue泛型函数通过[K comparable, V int64|fload64]声明了两个类型参数K,V,供函数参数和返回值使用。
类型参数K的类型必须为comparable类型,因为被用作map的key值,在Go语言中map的key值必须是可比较的类型。
类型参数V的类型可以是int64或float64,在声明时使用|组合支持的类型。
普通参数m 表示一个泛化的map,相应的返回值也是一个泛化的类型。
使用:

func TestSumValue(t *testing.T) {ints := map[string]int64{"one":   234,"two":   6755,"three": 78675,}floats := map[string]float64{"one":   123.456,"two":   7865.9658,"three": 87906.865,}t.Logf("sum ints : %v , floats : %v", SumValue(ints), SumValue[string, float64](floats))
}

执行结果
在这里插入图片描述

在调用泛型函数的地方,编译器会将泛型函数实例化,即使用真实的类型来替换类型参数,在调用时有两种方式:

  • 隐式调用: 调用泛型函数时使用缺省类型参数,让编译器根据实际的参数进行推导。(SumValue(ints))
  • 显示调用: 调用泛型函数时显式的指明类型参数。(SumValuestring, float64)

需要注意的是,编译器之所以能够推导出参数类型是因为函数存在入参,编译器通过传入的变量和函数的参数声明可以推导出参数类型,但对于没有函数参数的泛型函数来说,编译器
无法进行推导,也就无法实例化泛型函数,此时必须显式地调用并指定类型参数。
比如:
在这里插入图片描述

就无法推导出来返回值的类型了
而且显式调用,必须全部指定,不能指定部分类型
在这里插入图片描述

2. 泛型的特点

泛型的英文表述为generic,即一般化,泛化,具体来讲就是函数和类型的泛化。在泛型被引入之前一个函数所能接收的参数类型及
所能处理的数据类型是确定的,但泛型函数却能接受和处理多种类型,对于类型也是同样的道理。
泛型主要包含三方面的内容:

  1. 函数的泛化
  2. 类型的泛化
  3. 接口的扩展

2.1 函数泛化

为了支持泛型,Go语言函数扩展为可以接受一个使用方括弧表示的类型参数;
func SumValue1[K comparable, V int64 | float64, T int64 | float64](m map[K]V) T
同普通的函数参数类似,类型参数中的每个参数也有一个类型,比如参数K,V的类型分别为 comparable(伴随泛型而引入的内置interface类型,表示可比类型)
和int64|float64(表示int64或float64)。
函数中的类型参数是可选的,没有类型参数的函数是传统的函数,带有类型参数的函数则是泛型函数。
即便Go 1.18 引入了泛型并且扩展了函数,但仍然保持兼容(在这里小小的谴责一下 python 和 scala )。
类型参数中的类型正式的名称是类型约束,用来约束类型的范围。 上面额函数可以接受多种类型的map为参数,考虑到所有的map的key的类型都是comparable类型,
那么只要一个map的值类型是int64或float64就能调用泛型函数。
比如: map[int]int64,map[int64]int64,map[float64]float64,...

2.2 类型泛化

泛型同样扩展了类型的表示方法,允许在创建自定义类型时也能接受一个使用方括弧表示的类型参数。
type arr[T int|int64] []T
声明arr类型,可以容纳int或者int64的切片。
这种声明中带有类型参数的类型被称为泛型类型。
泛型类型必须通过类型参数实例化后才可以使用。
var arrInt arr[int]
var arrInt64 arr[int64]
但是当实例化允许范围之外的类型时,会编译异常
在这里插入图片描述

在实例化一个泛型类型时,必须指定类型参数(编译器无法自动推导)

泛型类型同普通类型一样,同样允许定义方法,但是其类型必须带上类型参数:

func (a *arr[T]) add(x T) {*a = append(*a, x)
}
func TestArrAdd(t *testing.T) {var a arr[int]a.add(3)a.add(4)t.Logf("res : %v", a)
}

执行结果
在这里插入图片描述

未泛型类型定义方法时,必须指定类型参数,但参数名可以与泛型类型声明不同。

func (a *arr[X]) add1(x X) {*a = append(*a, x)
}

定义时使用T,但是在使用的时候,可以与声明时的名字不同。
如果方法体中并未使用类型参数,甚至可以使用_省略

func (a *arr[_]) add2(x _) {*a = append(*a, x)
}

但是不管是换个名字还是使用_并没有任何好处,反而降低了可读性。

3. 类型约束

无论函数和类型如何泛化,都需要类型参数来限定其泛化的范围,类型参数使用类型的集合表示范围。

3.1 类型集合

func SumValue1[K comparable, V int64 | float64, T int64 | float64](m map[K]V) T
该函数的类型参数中K的类型限定为comparable,V 的类型限定为int64或float64。
comparable是interface类型,int64|float64是组合类型,都代表一个类型集合,用于约束泛化的范围。
使用|来组合多个类型,从而形成一个类型集合。

3.2 interface 类型集合

在泛型特性被引入之前,interface仅表示一个方法集合,实现了该方法结合的所有类型都可认为实现了这个interface。
在泛型的设计中,对interface进行了扩展,interface将不在仅仅表示方法集合,它还可用于表示类型集合,同理,集合内所有类型都可认为实现了这个interface。

3.2.1 内置interface类型集合

comparable就是跟随泛型被引入的内置interface类型
在这里插入图片描述

除了comparable还有any。
comparable表示可比较类型的集合,仅能用于类型参数中。
any不仅在类型参数中表示任意类型的集合,还可以在非泛型场景中作为interface{}的别名使用。

3.2.2 自定义interface类型集合

除了内置的comparable和any两种类型可作为类型约束使用,用户还可以使用interface来定义类型集合。
在泛型之前,interface类型中仅允许包含方法或内嵌interface两种元素,引入泛型后,interface类型将允许使用另外三种元素以表示一个类型集合:

  1. 任意类型元素(如 int)
  2. 近似类型元素(使用表示法,如int)
  3. 联合类型元素(使用|表示法,如int|int64)

需要注意的是,如果interface类型中使用了这三种元素的任意一种,那么这个interface只能用于泛型的类型参数

3.2.2.1 任意类型元素

任意类型(包含interface类型)都可以出现在一个新的interface类型中,用于表示一个仅用于类型参数的集合

type Mint interface {int
}func addMint[M Mint](m1, m2 M) M {return m1 + m2
}
func TestMint(t *testing.T) {t.Log(addMint(3, 4))
}

在这里插入图片描述

此时该interface表示的数据集仅包含一种类型,且仅能用于泛型场景中的类型参数中。
interface类型和自定义类型都可以出现在interface中从而表示一个类型集合。
可以定义新的泛型interface,不能使用泛型interface定义interface 方法集合
interface泛型用于interface
在这里插入图片描述

但是不能将interface泛型用于interface方法集合
在这里插入图片描述

但是如果显式的声明了泛型,那么就可以使用
在这里插入图片描述

并且该interface的方法集合也能像之前一样实现
在这里插入图片描述

因为在定义interface泛型的时候,限定是int,所以只有int类型才算是实现了方法
在这里插入图片描述

这样来看,使用interface泛型类型,可以限定什么样的方法算是实现。

如果将float64加入到interface泛型中,那么float64的方法也算是实现
在这里插入图片描述

3.2.2.2 近似类型元素

在使用 interface声明类型集合时,可以使用~<type>来制定一组类型,只要其底层类型为同一类型即包含在这个集合中。
因为在Go中,可以通过type取别名,而泛型又时通用这个含义。
比如创建一个string的泛型函数,但是因为使用了type对string取了别名,结果别名类型就无法使用泛型函数。
近似类型元素就是可以让type取了别名的类型也能使用
不使用近似类型
在这里插入图片描述

使用近似类型
在这里插入图片描述

只要底层类型相同,就能使用泛型函数

需要注意的是,~之后的类型必须是某个底层类型,换句话说,一个类型的底层类型不是自身就不能使用~
在这里插入图片描述

另外,interface 自身也不能用于定义近似类型集合,因为interface的底层类型并不确定。

3.2.2.3 联合类型元素

前面使用~定义的元素集合仅能包括一组底层类型一致的类型,又是可能需要联合多种类型,甚至联合多种底层类型一致的类型,此时可以用
|定义一个更宽泛的类型集合

type MInteger interface {int | int8 | int16 | int32 | int64
}

但是上述定义仅能支持底层类型,不支持别名
更进一步,可以把所有底层类型也包含进来

type MAnyInteger interface {~int | ~int8 | ~int16 | ~int32 | ~int64
}

这样即使是别名类型,也能支持。

3.2.3 interface类型集合运算

前面使用interface声明类型集合时,均使用一行代码制定一个集合(一个子集),事实上interface支持按行制定多个自己和,这些自己和取交集形成最终的集合

type NewString interface {~stringstring
}

NewString的类型集合由两个子集组成,一个是所有底层类型为string的集合,另一个是string单一类型,两个子集取交集,最终的类型集合将只包含string单一类型
在这里插入图片描述

3.2.4 基于操作的类型集合

假设顶一个泛型函数来比较元素大小

type Ordered interface {~int|~int8|~int16|~int32|~int64|~uint|~uint8|~uint16|~uint32|~uint64|~float32|~float64|~string
}func Equals[T Ordered](a, b T) bool {if a == b {return true}return false
}

定义的Ordered泛型类型是全部可以使用==比较的底层类型,并且包含别名类型,泛型函数限定了Ordered泛型类型。
copmarable和Ordered类似,范围更大。

4. 小例子

4.1 map.Keys 获取map的全部key

将map中的所有key取出来,然后存入切片中返回

func Keys[K comparable, V any](m map[K]V) []K {res := make([]K, 0, len(m))for k, _ := range m {res = append(res, k)}return res
}

类型参数K被用于声明了一个泛型的切片,然后把遍历到的key添加到切片中并返回。
任意的map都能使用Keys泛型函数

func TestKeys(t *testing.T) {t.Log(Keys(map[string]struct{}{"one":   {},"tow":   {},"three": {},}))t.Log(Keys(map[int]int{1: 1,2: 2,3: 3,}))
}

在这里插入图片描述

4.2 Set

Set可以存储一组不重复的数据,广泛用于需要去重的场景。很多编程语言比如Java,C++都提供了相应的实现,但是在Go语言中并没有Set类型。
有了泛型可以自己实现了

// 定义 Set
type Set[T comparable] map[T]struct{}// 创建 Set
func MakeSet[T comparable]() Set[T] {return make(Set[T])
}// 添加元素
func (s Set[T]) Add(k T) {s[k] = struct{}{}
}// 删除元素
func (s Set[T]) Delete(k T) {delete(s, k)
}// 判断是否包含
func (s Set[T]) Contains(k T) bool {_, ok := s[k]return ok
}// 返回长度
func (s Set[T]) Len() int {return len(s)
}// 遍历
func (s Set[T]) Iterate(f func(T)) {for k := range s {f(k)}
}func TestSet(t *testing.T) {set := MakeSet[int]()set.Add(1)set.Add(2)set.Add(1)set.Add(3)t.Log(set.Len()) // 预期 3t.Log(set.Contains(2)) // 预期 trueset.Delete(1) t.Log(set.Len()) // 预期 2t.Log(set.Contains(1)) // 预期 falsesum := 0set.Iterate(func(i int) {sum += i})t.Log(sum) // 预期 5
}

在这里插入图片描述

使用泛型实现的Set可适用于任意的可比较类型,行为与其他语言实现的Set基本类似,但是只能函数调用,不能使用下标操作访问元素。
上面实现的Set底层使用一个map实现,并不是线程安全的,还可以进一步使用自定义扩展

type SyncSet[C comparable] struct {l sync.RWMutexm map[C]struct{}
}

在读操作的时候,加读锁,在写操作的时候加写锁。

4.3 排序 Sort

要对切片中的元素进行排序,在标准库提供sort.Slice之前,每种类型的切片都需要实现sort.Interface接口中的三个方法
在这里插入图片描述

然后使用sort.Sort方法进行排序,即便后来标准库中引入了sort.Slice,但是使用时仍然需要提供一个排序函数。
使用泛型实现一个针对切片的通用排序函数

type Ordered interface {~int | ~int8 | ~int16 | ~int32 | ~int64 |~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 |~float32 | ~float64 |~string
}type orderSlice[O Ordered] []Ofunc (o orderSlice[O]) Len() int {return len(o)
}
func (o orderSlice[O]) Less(i, j int) bool {return o[i] < o[j]
}
func (o orderSlice[O]) Swap(i, j int) {o[i], o[j] = o[j], o[i]
}
func OrderSlice[O Ordered](s []O) {// s 被转换为 []Ordered 类型,也就是 orderSlice,然后排序// 因为 orderSlice已经实现了排序的接口,不需要额外实现了sort.Sort(orderSlice[O](s))
}
func TestOrder(t *testing.T) {is := []int{3, 4, 5, 1, 2}OrderSlice(is)t.Log(is)ss := []string{"he", "ww", "ss"}OrderSlice(ss)t.Log(ss)
}

在这里插入图片描述

使用泛型实现排序幻术也有一定的局限性,因为不容易处理复杂的符合类型,比如自定义的struct类型。

5. 总结

反形式衡量编程语言技术完备度的一个重要参考指标,但是也是一个比较争议的技术。
泛型的缺失导致开发者不得不编写重复的代码,或者编写相对通用但缺少类型安全的代码,甚至有些项目使用代码自动生成技术来摆脱编写
重复代码的烦恼,从这方面来看,Go确实需要泛型。
但是引入泛型也是有一定成本的,比如泛型的三个困局:

  • 没有泛型(C语言)会降低程序员的生产力,但不会增加语言的复杂度
  • 泛型会增加编译器的负担(C++),可能会编译出很多冗余的代码,进而拖慢编译时间
  • 泛型会降低运行时的性能(Java),避免编译大量冗余代码的后果是增加运行时的开销

Go语言早在1.17版本时就推出了试用版本,但在1.18中还是用了极大的篇幅说明泛型的种种风险。
https://golang.google.cn/doc/go1.18#generics

相关文章:

Go-知识泛型

Go-知识泛型 1. 认识泛型1.1 不使用泛型1.2 使用泛型 2. 泛型的特点2.1 函数泛化2.2 类型泛化 3. 类型约束3.1 类型集合3.2 interface 类型集合3.2.1 内置interface类型集合3.2.2 自定义interface类型集合3.2.2.1 任意类型元素3.2.2.2 近似类型元素3.2.2.3 联合类型元素 3.2.3 …...

Qt 如何 发送与解析不定长报文以及数组不定长报文

文章目录 割方式一,采用QDataStream 解析,可直接设定大小端解析,无需自己转换方式二,采用结构体字节对齐方式解析发送接收方割 方式一,采用QDataStream 解析,可直接设定大小端解析,无需自己转换 需要注意的是结构体定义要去掉字节对齐,否则会崩溃,因为由自定义数据结…...

Rust默认使用UTF-8编码来解析源代码文件。如果在代码中包含无法用UTF-8编码表示的字符,编译器会报错!

文章目录 Rust默认编码示例在ANSI编码下中文显示正常的代码在UTF-8编码下将显示不正常在编译时&#xff0c;Rust使用UTF-8编码来解析代码&#xff0c;发现无法用UTF-8编码表示的字符&#xff0c;于是编译器报错 Rust默认编码 Rust 语言默认使用 UTF-8 编码来解析源代码文件。如…...

【jeston】torch相关环境安装

参考&#xff1a;玩转NVIDIA Jetson &#xff08;25&#xff09;— jetson 安装pytorch和torchvision 我的jeston信息&#xff1a; torch install 安装环境 conda create -n your_env python3.8 conda activate your_envpytorch_for_jeston 安装.whl文件 验证&#xff1…...

[CR]厚云填补_大型卫星影像去云数据集

AllClear: A Comprehensive Dataset and Benchmark for Cloud Removal in Satellite Imagery Abstract 卫星图像中的云对下游应用构成了重大挑战。当前云移除研究的一个主要挑战是缺乏一个全面的基准和一个足够大和多样化的训练数据集。为了解决这个问题&#xff0c;我们引入了…...

Langchain CharacterTextSplitter无法分割文档问题

在使用Langchain的文档分割器时&#xff0c;使用CharacterTextSplitter拆分文档是&#xff0c;发现返回的文档根本没有变化&#xff0c;即使设置了chunk_size&#xff0c;返回的大小也不符合参数设置。 CharacterTextSplitter设置了150&#xff0c;但是根本没有处理&#xff0…...

ros service不走是为什么

在ROS&#xff08;Robot Operating System&#xff09;中&#xff0c;如果ROS服务&#xff08;Service&#xff09;没有正常工作&#xff0c;可能有多种原因。你可以检查以下几点来排查问题&#xff1a; 服务是否正确启动 首先&#xff0c;确保服务节点已经启动并注册了相应的…...

量子计算机的原理与物理实现

量子计算机的原理与物理实现很复杂 指导性原则 首先思考制备一台量子计算机需要些什么&#xff1f; 需要量子比特——二能级量子系统。除了量子计算机需要满足一些物理特性&#xff0c;它还必须要把量子比特绘制到某种初态上&#xff0c;以及测量系统的输出态。 而实验上的挑战…...

SQL Server 常用关键词语法汇总

一、函数 1.1 CAST CAST ( expression AS data_type [ ( length ) ] )expression: 这是你想要转换的数据或表达式。data_type: 目标数据类型&#xff0c;比如 INT, VARCHAR, DATE 等等。(length): 对于某些数据类型&#xff08;如 CHAR, VARCHAR, BINARY, VARBINARY&#xff…...

软件测试工程师面试整理 —— 操作系统与网络基础!

在软件测试中&#xff0c;了解操作系统和网络基础知识对于有效地进行测试工作至关重要。无论是在配置测试环境、调试网络问题&#xff0c;还是在进行性能测试和安全测试时&#xff0c;这些知识都是不可或缺的。 1. 操作系统基础 操作系统&#xff08;Operating System, OS&am…...

网络安全防御策略:通过限制IP访问提升服务器安全性

标题&#xff1a;网络安全防御策略&#xff1a;通过限制IP访问提升服务器安全性 摘要&#xff1a; 在网络安全领域&#xff0c;服务器被入侵是一场严重的事故。一旦发生这种情况&#xff0c;除了立即采取措施恢复系统外&#xff0c;还需要加强后续的安全防护措施。本文将探讨为…...

Multiprocessing出错没有提示was skipped without notice in python

这个问题可以通过打印返回结果解决。 解决方法 比如 Pool.apply_async(csdnKuangXiaoHU, args=(p, DestFile))改成 Result = Pool.apply_async(csdnKuangXiaoHU, args=...

调整应用窗口透明度

朋友问我有没有软件透明得&#xff0c;一开始没理解&#xff0c;他给我发一个&#xff0c;我一看原来时调整窗口透明度得&#xff0c;想着python应该也可以实现&#xff0c;就写了一个。 效果图如下&#xff1a; 源码如下&#xff1a; import sys import ctypes from PySid…...

启智畅想集装箱号码智能识别原理,OCR识别应用

集装箱号码用途&#xff1a; 集装箱号码在填写托运单时是必填项&#xff0c;用于标识和跟踪货物运输过程中的集装箱。它有助于海关管理和物流跟踪&#xff0c;确保货物能够顺利通过海关检查并按时送达目的地。 集装箱号码智能识别原理&#xff1a; 在深入探讨集装箱号码OCR&…...

React基础知识

说明&#xff1a;react版本为 18.3.1 React是什么 React由Meta公司研发&#xff0c;是一个用于构建Web和原生交互界面的库。&#xff08;开发基于浏览器的web应用和基于mac和android的移动应用&#xff09;React的优势 1.相较于传统基于DOM开发的优势&#xff1a;组件化的开…...

Java基础:面向对象编程3

1 Java可变长参数 1.1 概述 Java 的可变长参数&#xff08;Varargs&#xff09;是在 Java 1.5 中引入的功能&#xff0c;允许方法接受任意数量的相同类型的参数。可变参数的语法是在参数类型后面加上三个点&#xff08;...&#xff09;&#xff0c;例如 int... numbers。 1.…...

实验kubernetes的CPU绑定策略

CPU 管理配置 CPU 管理策略通过 kubelet 参数 --cpu-manager-policy 或 KubeletConfiguration 中的 cpuManagerPolicy 字段来指定。 支持两种策略&#xff1a; none&#xff1a;默认策略。static&#xff1a;允许为节点上具有某些资源特征的 Pod 赋予增强的 CPU 亲和性和独占…...

Zsh 安装与配置

目录 1 环境配置 1.1 基本工具安装 1.2 安装 oh-my-zsh 1.3 从.bashrc中迁移配置&#xff08;可选&#xff09; 2 主题配置 2.1 内置主题 2.2 自定义主题 2.2.1 推荐主题 3 插件安装 3.1 推荐插件 3.1.1 zsh -autosuggestions 3.1.2 zsh-syntax-highlighting 3.2 启…...

Redis可视化工具Redis Desktop Manager(附安装包)

前言 redis工具&#xff0c;我相信每个开发都需要&#xff0c;如果每次查都去client执行指令&#xff0c;我怕查完之后&#xff0c;老大就要发版咯。我之前一直用的Redis可视化工具RedisDesktopManager&#xff0c;总觉得差点意思&#xff0c;直到同事推荐了个新的&#xff0c…...

sql server删除过期备份文件脚本

一、通过脚本查看过期文件&#xff0c;时间可以自己设定 for /f "delims" %i in (dir /b /a-d "E:\mybak_file\*.bak" ^| findstr /i "backup" ^| findstr /v /i "no_backup") do if "%~ti" LSS "2024/09/29 16:50&qu…...

【Docker系列】Docker查看镜像架构

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…...

Python案例 | 测试网络的下载速度上传速度和 ping 延迟

使用了 speedtest 库来测试网络的下载速度上传速度和 ping 延迟 注意&#xff0c;这里需要先卸载speedtest&#xff0c;再安装speedtest-cli pip uninstall speedtest pip install speedtest-cli其次运行代码&#xff1a; # 使用了 speedtest 库来测试网络的下载速度上传速度…...

一键找回,2024四大固态硬盘数据恢复工具推荐!

虽然固态硬盘&#xff08;SSD&#xff09;因其读写速度快、功耗低等特点受到广泛欢迎&#xff0c;但它并非无懈可击&#xff0c;数据丢失的问题依然存在。如果你也遇到了固态硬盘数据丢失的问题&#xff0c;那么一下的这几款软件可以一试&#xff01; 福昕数据恢复 直达链接&…...

数据结构~AVL树

文章目录 一、AVL树的概念二、AVL树的定义三、AVL树的插入四、AVL树的平衡五、AVL树的验证六、AVL树的删除七、完整代码八、总结 一、AVL树的概念 AVL树是最先发明的自平衡二叉查找树&#xff0c;AVL是⼀颗空树&#xff0c;或者具备下列性质的二叉搜索树&#xff1a;它的左右子…...

ffmpeg面向对象——rtsp拉流探索(1)

目录 0.avformat_open_input的rtsp流程程纯净版1.rtsp拉流流程图2.rtsp拉流对象图 标准rtsp协议的基石是tcp&#xff0c;本节探索下ffmpeg的rtsp拉流协议tcp的创建及rtsp协商过程。 0.avformat_open_input的rtsp流程程纯净版 ffmpeg拉流&#xff0c;从avformat_open_input接口…...

【启明智显分享】ZX7981PM WIFI6 5G-CPE:2.5G WAN口,2.4G/5G双频段自动调速

昨天&#xff0c;我们向大家展现了ZX7981PG WIFI6 5G-CPE&#xff0c;它强大的性能也引起了一波关注&#xff0c;与此同时&#xff0c;我们了解到部分用户对更高容量与更高速网口的需求。没关系&#xff01;启明智显早就预料到了&#xff01;ZX7981PM满足你的需求&#xff01; …...

openresty“热部署“lua

一、前言 频繁reload 或者restart影响测试使用nginx&#xff0c;修改lua脚本后要实际查看效果值&#xff0c;使用关闭lua代码缓存&#xff0c;可以实现实时查看代码效果。 每次请求都会从磁盘中加载lua脚本&#xff0c;生产上面不要开启&#xff0c;影响响应速度 二、修改ngin…...

基于SpringBoot+Vue+MySQL的企业招聘管理系统

系统展示 用户前台界面 管理员后台界面 企业后台界面 系统背景 在当今数字化转型的大潮中&#xff0c;企业对于高效、智能化的人力资源管理系统的需求日益增长。招聘作为人力资源管理的首要环节&#xff0c;其效率与效果直接影响到企业的人才储备与竞争力。传统的招聘方式不仅耗…...

vue3之defineComponent

defineComponent 是 Vue 3 中提供的一个辅助函数&#xff0c;用于定义组件。它可以帮助你更好地利用 TypeScript 的类型推断和 IDE 的自动补全功能。defineComponent 主要用于组合式 API&#xff08;Composition API&#xff09;和单文件组件&#xff08;SFC&#xff09;。 使…...

springboot+vue家政服务管理平台

作者&#xff1a;计算机学长阿伟 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、ElementUI等&#xff0c;“文末源码”。 系统展示 【2024最新】基于JavaSpringBootVueMySQL的&#xff0c;前后端分离。 开发语言&#xff1a;Java数据库&#xff1a;MySQL技术&#xff1a;…...