商务网站建设心得体会网站建设与管理课程视频

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

商务网站建设心得体会,网站建设与管理课程视频,wordpress允许ping,蓝色 宽屏 网站 模板下载7.2 泛型的使用与实现分析 泛型是Go 1.18引入的概念#xff0c;在引入这个概念前经过了好几年的考量最终才将这这个特性加进去。 泛型在多种语言中都是存在的#xff0c;比如C、Java等语言中都有泛型的概念。 本节我们将针对泛型的使用、实现原理进行整体的讲解。 本节代…7.2 泛型的使用与实现分析 泛型是Go 1.18引入的概念在引入这个概念前经过了好几年的考量最终才将这这个特性加进去。 泛型在多种语言中都是存在的比如C、Java等语言中都有泛型的概念。 本节我们将针对泛型的使用、实现原理进行整体的讲解。 本节代码存放目录为 lesson20 泛型基础 什么是泛型 简单来说泛型与空接口interface{}相似但又有不同。我们知道空接口可以用来标识任意的类型其实泛型也是干这件事情的。 那么既然有了接口为什么还要出现泛型呢这需要结合我们之前章节的反射来一起看待。 在我们使用interface{}与反射来进行处理时其实都是在运行时处理运行时处理那么不可避免的就会出现性能开销与安全性问题。 而泛型则是在编译阶段进行处理的而不是运行时处理所以不管是从性能还是安全性来说泛型都是一种更好的选择。 另外泛型主要用于函数与类型的的定义而不能用于普通变量的定义这也是与interface{}的主要区别。 泛型的主要应用是在函数的定义上。当我们有一些公用函数比如说打印、求和等在没有泛型的时候我们需要定义一个参数为int型的Print、一个参数为string型的Print但是如果是泛型的话我们中需要定义一个即可。 泛型函数的实现与应用 简单泛型函数 func PrintT any {fmt.Println(input) }Print(1) Print(hello)在上面的代码中我们通过泛型仅定义了一个函数即实现了传递int、string参数的目的。 定义的格式也是固定的func funcNameT any其中[T any]就标识这个函数是一个泛型函数。 多个类型参数 func AddT int | float64 T {return a b }fmt.Println(Add(1, 2)) fmt.Println(Add(1.5, 2.3))在上面的代码中我们传入了多个参数同时我们可以看到使用了[T int | float64]这样的格式。 那么这种格式是什么意思呢如果我们这样写其实就代表这个函数接收的参数只能是int、float64两种类型的。 基于我们函数的功能如果传入string、结构体等类型的参数那么肯定是不符合的所以我们可以在函数中就指定好传入的类型范围。 泛型结构体 在结构体中使用泛型也是比较常用的一个操作比如我们的结构体字段是相同的但是会接收不同类型的值那么使用泛型也是一个很好的选择。 type Container[T any] struct {value T }intContainer : Container[int]{value: 42} fmt.Println(intContainer.value)stringContainer : Container[string]{value: hello} fmt.Println(stringContainer.value)结构体泛型使用会比较广泛特别是在一些算法或数据结构类型的场景。比如说实现一个栈、一个队列那么我们就可以使用泛型来实现这样栈就可以存储多种数据类型。 type Stack[T any] struct {items []T }func (s *Stack[T]) Push(item T) {s.items append(s.items, item) }func (s *Stack[T]) Pop() T {n : len(s.items)item : s.items[n-1]s.items s.items[:n-1]return item }// 创建一个整数栈 intStack : Stack[int]{} intStack.Push(1) intStack.Push(2) fmt.Println(intStack.Pop())// 创建一个字符串栈 stringStack : Stack[string]{} stringStack.Push(hello) stringStack.Push(world) fmt.Println(stringStack.Pop())通过泛型我们就可以简单的进行处理这种方法其实是比interface{}高效很多的。 泛型的约束与接口 基本泛型约束 // Compare 约束 T 必须可比较(类型必须实现了comparable接口) func CompareT comparable bool {return a b }fmt.Println(Compare(1, 2)) fmt.Println(Compare(Go, Go))在上面的代码中T类型参数使用了comparable作为约束表示T必须是支持比较操作的类型例如整数、字符串等。 comparable是Go的内置接口用于表示可以比较的类型支持 和 ! 操作。 自定义接口作为约束 // Stringer 定义一个接口 type Stringer interface {String() string }// PrintString 泛型函数T 必须实现 Stringer 接口 func PrintStringT Stringer {fmt.Println(item.String()) }// Person 实现 Stringer 接口的类型 type Person struct {Name string }func (p Person) String() string {return p.Name }在这个例子中泛型函数PrintString限定类型参数T必须实现Stringer接口。 也就是说PrintString只能用于那些实现了Stringer接口的类型比如Person。 内置的泛型约束 // Number 泛型约束 T 必须是 int 类型的别名 type Number interface {~int }func SumT Number T {return a b }type MyInt int // MyInt 是 int 的别名var a MyInt 10 var b MyInt 20 fmt.Println(Sum(a, b))在上面的代码中~int表示类型参数T可以是int或任何int 的别名类型如 MyInt。
实现原理 如果了解Java的话我们可以知道Java只要函数参数的类型不同那么函数名称可以是相同的。 在Go语言中泛型其实差不多就是这么实现的。在编译的时候编译器会生成多个类型的函数。 如下代码所示 func PrintT any {fmt.Println(input) }Print(1) Print(hello)在上面的代码中我们实现了一个简单的打印函数调用的时候传入了int与string类型的数据。 那么在我们编译的时候编译器可能会生成下面的代码 func Print1int {fmt.Println(input) }func Print2string {fmt.Println(input) }执行的大概示意图如下所示

泛型函数 Print[T]

| 泛型代码 | —————–|Monomorphization(为不同值类型生成副本)|————| PrintInt() | // 为 int 类型生成的函数副本————| PrintStr() | // 为 string 类型生成的函数副本————| PrintF64() | // 为 float64 类型生成的函数副本————Go的泛型使用了多种方式上面描述的属于其中的一种方式也就是单态化这种方式主要应用于参数是值的函数。 上面我们提到的这种方式虽然简单但是如果函数副本太多的话最终编译出来的二进制文件肯定是很大的所以还采用了虚拟方法表的方式。 当泛型函数接收的是指针类型或接口类型时编译器会为它生成一个字典表。这个表类似于虚拟方法表记录了如何在运行时处理不同类型的操作。 我们可以通过下面的示意图来理解

编译时

| 编译器检查到 Person 实现了 Stringer 接口 |

——————————————–|v

| 生成 Person 的虚拟方法表VMT | | 包含 String() 指向 Person.String 的指针 |

—————————————–运行时

| 调用 PrintString(p) |

————————————-|v

| 查找 p 的虚拟方法表 | – 找到 Person.String() 方法

—————————|v

| 调用 Person.String() | ———————-虚拟方法表比较抽象我们以一句话理解就可以调用的时候会去查找PrintString(p)中p的方法表最终找到了Person.String()这时候就直接执行就可以了。 Go语言的泛型实现还在持续优化中我们可以持续关注现阶段掌握泛型的使用即可。 小结 本节我们讲解了泛型的基础概念、使用以及简单的实现原理。泛型为Go语言带来了更大的灵活性帮助开发者编写更具通用性的代码。 在框架开发、工具开发场景应用比较广泛通过泛型我们可以简单的将代码合并优化。 我的GitHubhttps://github.com/swxctx 书籍地址https://d.golang.website/ 书籍代码https://github.com/YouCanGolang/GoDeeperCode