【魅力golang】之-泛型

早期的golang版本是不支持泛型的,这对于从其它语言转型做go开发的程序员来说,非常不友好,自 1.18开始golang正式支持泛型,解决了开发者在编写通用代码时的需求。泛型通过类型参数允许函数和数据结构支持多种类型,从而提升代码的可复用性和灵活性。

1泛型的意义

1.1 什么是泛型

泛型就是广泛的数据类型,或者叫扩展的类型、增加的类型,其本质是参数化类型,指在定义函数或数据结构时使用类型参数,以便可以在调用时指定具体的类型。它允许开发者编写通用代码,而无需为每种数据类型编写单独的实现。

1.2 为什么需要泛型

在 Go 的早期版本中,处理不同类型的通用逻辑需要使用接口或类型断言。这种方式虽然灵活,但牺牲了类型安全性和性能。泛型的引入解决了以下问题:

  1. 代码复用性:避免为不同类型编写重复逻辑。
  2. 类型安全性:在编译时确保类型一致性,减少运行时错误。
  3. 性能优化:避免接口和类型断言带来的额外开销。

示例:没有泛型的通用函数

package mainimport "fmt"func addInts(a, b int) int {return a + b
}func addFloats(a, b float64) float64 {return a + b
}func main() {fmt.Println(addInts(1, 2)) // 输出: 3fmt.Println(addFloats(1.1, 2.2)) // 输出: 3.3000000000000003
}

输出:

3
3.3000000000000003(这里请大家先忽略精度丢失问题,后面风云会单独发文详细阐述,今天主要讲泛型,下同)

上述代码需要为每种数据类型分别实现函数。使用泛型后,可以实现统一的逻辑。

2Go 泛型的设计思路

Go 的泛型设计注重简单性和实用性。其关键点如下:

  1. 类型参数:通过类型参数化函数和结构体,实现多种类型的支持。
  2. 类型约束:使用接口定义类型参数的限制,明确泛型函数可用的操作。
  3. 简单与一致:Go 泛型设计避免了过度复杂性,保持语言的简洁性。

3泛型的基本用法

3.1 泛型函数

在 Golang 中,使用方括号 [] 定义类型参数。

示例:泛型函数

package mainimport "fmt"// 泛型函数
func add[T int | float64](a, b T) T {  // T 表示泛型类型return a + b
}func main() {fmt.Println(add(1, 2)) // 输出: 3fmt.Println(add(1.1, 2.2)) // 输出: 3.3000000000000003
}
  • T:表示类型参数。
  • int | float64:类型约束,表示 T 可以是 int 或 float64。

3.2 泛型结构体

泛型可以用于结构体,使其支持多种类型。

示例:泛型结构体

package mainimport "fmt"// 泛型结构体
type Pair[T any] struct {  // T 表示泛型类型First T  // First 和 Second 分别表示泛型类型的两个字段Second T
}func main() {p1 := Pair[int]{First: 1, Second: 2}  // 创建一个 Pair[int] 类型的实例p2 := Pair[string]{First: "Hello", Second: "World"} // 创建一个 Pair[string] 类型的实例fmt.Println(p1) // 输出: {1 2}fmt.Println(p2) // 输出: {Hello World}
}
  • any类型实际上是interface{}的别名,两者在所有方面都是等价的‌‌1any类型的引入主要是为了在泛型中使用时简化语法,减少括号的使用‌。

3.3 类型约束

Go 使用接口定义类型约束,指定类型参数的范围。

示例:使用类型约束

package mainimport "fmt"// 定义一个约束
type Number interface {int | float64
}// 使用约束的泛型函数
func multiply[T Number](a, b T) T {return a * b
}func main() {fmt.Println(multiply(2, 3)) // 输出: 6fmt.Println(multiply(1.5, 2.0)) // 输出: 3
}

通过类型约束,确保泛型函数支持的操作是合法的。

4泛型的应用场景

4.1 通用容器

泛型适合实现通用容器,如列表、队列、栈等。

示例:通用列表

package mainimport "fmt"// 定义一个泛型切片
type List[T any] struct {items []T
}// 添加一个元素到切片中
func (l *List[T]) Add(item T) { // 泛型方法l.items = append(l.items, item) // 添加一个元素到切片中
}func (l *List[T]) Get(index int) T { // 泛型方法return l.items[index] // 返回指定索引的元素
}func main() {intList := List[int]{} // 定义一个整数泛型切片intList.Add(1) // 添加元素intList.Add(2) // 添加元素fmt.Println(intList.Get(0)) // 输出: 1stringList := List[string]{} // 定义一个字符串泛型切片stringList.Add("Hello") // 添加元素stringList.Add("World") // 添加元素fmt.Println(stringList.Get(1)) // 输出: World
}

4.2 数据操作

使用泛型实现通用的数据操作函数,如查找、过滤、映射等。

示例:通用查找函数

package mainimport "fmt"// 查找函数
func find[T comparable](arr []T, target T) int { // 泛型函数for i, v := range arr { //遍历if v == target { // 使用泛型类型 Treturn i}}return -1
}func main() {nums := []int{1, 2, 3, 4}  // 使用泛型类型 intfmt.Println(find(nums, 3)) // 输出: 2words := []string{"Go", "Python", "Java"} // 使用泛型类型 stringfmt.Println(find(words, "Python"))        // 输出: 1
}
  • comparable:预定义约束,表示类型支持 == 和 !=。

4.3 自定义算法

泛型适合实现通用算法,如排序、归并等。

示例:通用排序

package mainimport ("fmt""sort"
)// 泛型排序函数
func sortSlice[T int | float64](arr []T) {sort.Slice(arr, func(i, j int) bool { // 使用泛型类型作为比较函数return arr[i] < arr[j] // 使用泛型类型进行比较})
}func main() {nums := []int{4, 2, 3, 1} // 使用int类型sortSlice(nums)           // 使用泛型排序函数fmt.Println(nums)         // 输出: [1 2 3 4]floats := []float64{3.1, 1.2, 2.3} // 使用float64类型sortSlice(floats)                  // 使用泛型排序函数fmt.Println(floats)                // 输出: [1.2 2.3 3.1]
}

5泛型的特点与注意事项

5.1 特点

  1. 类型安全:在编译时进行类型检查,减少运行时错误。
  2. 代码复用:通过泛型减少代码重复。
  3. 灵活性:支持任意类型的动态组合。

5.2 注意事项

  1. 性能问题:泛型代码可能在编译时生成多种类型的实现,可能增加二进制文件大小。
  2. 约束复杂性:复杂的类型约束可能降低代码的可读性。
  3. 接口 vs 泛型:在某些场景下,使用接口比泛型更简单。

示例:接口更适合的场景

对于需要操作不同类型的值但无需类型安全的场景,接口更为简洁。

package mainimport "fmt"func printValues(values []interface{}) { // 使用 interface{} 类型作为参数// 遍历 values 切片,打印每个元素的值。使用 range 语句来迭代每个元素,无需关心切片长度。for _, v := range values {fmt.Println(v)}
}func main() {printValues([]interface{}{1, "Hello", 3.14}) // 输出: 1, Hello, 3.14
}

6总结

Go 中的泛型通过类型参数和类型约束,使开发者能够编写更加灵活、高效的代码。尽管泛型强大,但应根据具体场景选择最合适的工具。在简单场景中,接口可能更为直观,而泛型则适合需要类型安全的复杂逻辑。合理使用泛型可以显著提升代码的可维护性和复用性。

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

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

相关文章

输入输出流 - cin, cout 的使用

引言 在编程中&#xff0c;输入和输出是与用户交互的重要方式。C 提供了标准输入输出流 cin 和 cout 来处理这些操作。本文将详细介绍如何使用 cin 和 cout 进行基本的输入和输出操作&#xff0c;并通过实例帮助读者更好地理解和掌握这些概念。 一、标准输出流 cout cout 是 …

数据结构(Java)——链表

1.概念及结构 链表是一种 物理存储结构上非连续 存储结构&#xff0c;数据元素的 逻辑顺序 是通过链表中的 引用链接 次序实现的 。 2.分类 链表的结构非常多样&#xff0c;以下情况组合起来就有 8 种链表结构&#xff1a; &#xff08;1&#xff09;单向或者双向 &#xff08;…

pdf有密码,如何实现pdf转换word?

PDF想要转换成其他格式&#xff0c;但是当我们将文件拖到PDF转换器进行转换的时候发现PDF文件带有密码怎么办&#xff1f;今天分享PDF有密码如何转换成word方法。 方法一、 PDF文件有两种密码&#xff0c;打开密码和限制编辑&#xff0c;如果是因为打开密码&#xff0c;建议使…

C++ 面向对象编程:继承中构造与析构函数顺序、继承中的同名属性访问、继承中的同名函数访问

在继承中&#xff0c;构造链中&#xff0c;先构造的后析构 见以下代码示例&#xff1a; #include<iostream> using namespace std;class animal1 { public:animal1() {cout << "animal1 构造" << endl;}~animal1() {cout << "animal1…

Springboot项目下面使用Vue3 + ElementPlus搭建侧边栏首页

Springboot项目下面、在html 页面 Vue3 ElementPlus 搭建侧边栏首页 1、效果图 2、static 文件下面的项目结构 3、代码实现 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>首页</title><…

Segment Routing Overview

大家觉得有意义和帮助记得及时关注和点赞!!! Segment Routing (SR) 是近年来网络领域的一项新技术&#xff0c;“segment” 在这里 指代网络隔离技术&#xff0c;例如 MPLS。如果快速回顾网络设计在过去几十年的 发展&#xff0c;我们会发现 SR 也许是正在形成的第三代网络设计…

【Rust自学】7.3. use关键字 Pt.1:use的使用与as关键字

喜欢的话别忘了点赞、收藏加关注哦&#xff0c;对接下来的教程有兴趣的可以关注专栏。谢谢喵&#xff01;(&#xff65;ω&#xff65;) 7.3.1. use的作用 use的作用是将路径导入到当前作用域内。而引入的内容仍然是遵守私有性原则&#xff0c;也就是只有公共的部分引入进来才…

如何在Express.js中定义多个HTTP方法?

在 Express.js 中定义多个 HTTP 方法的路由&#xff0c;你可以选择几种不同的方式来实现。以下是两种主要的方法&#xff1a; 1. 使用 app.route() app.route() 提供了一种链式定义多个HTTP方法的能力&#xff0c;这有助于避免重复书写相同的路径。这种方式特别适合当同一个路…

讲一个自己写的 excel 转 html 的 java 工具

由来 这是一个从开发需求中诞生的工具&#xff0c;在工作中因为有一个 excel 转 html 的任务&#xff0c;又没找到一个专门做这方面的工具&#xff08;其他工具几乎都是简单的转换&#xff0c;无法还原 excel 样式&#xff0c;而且转换的宽高有点儿差距&#xff09;&#xff0…

Cursor提示词

你是一位经验丰富的项目经理&#xff0c;对于用户每一次提出的问题&#xff0c;都不急于编写代码&#xff0c;更多是通过深思熱虑、结构化的推理以产生高质量的回答&#xff0c;探索更多的可能方案&#xff0c;并从中寻找最佳方案。 约束 代码必须可以通过编译回答尽量使用中…

USB 状态机及状态转换

文章目录 USB 状态机及状态转换连接状态供电状态默认状态地址状态配置状态挂起状态USB 状态机及状态转换 枚举完成之前,USB 设备要经过一系列的状态变化,才能最终完成枚举。这些状态是 连接状态 - attached供电状态 - powered默认状态 - default地址状态 - address配置状态 -…

如何在短时间内读懂复杂的英文文献?

当我们拿起一篇文献开始阅读时&#xff0c;就像是打开了一扇通往未知世界的大门。但别急着一头扎进去&#xff0c;咱们得像个侦探一样&#xff0c;带着疑问去探险。毕竟&#xff0c;知识的海洋深不可测&#xff0c;不带点“装备”怎么行&#xff1f;今天就聊聊&#xff0c;平时…

VS Code AI开发之Copilot配置和使用详解

随着AI开发工具的迅速发展&#xff0c;GitHub Copilot在Cursor、Winsuf、V0等一众工具的冲击下&#xff0c;推出了免费版本。接下来&#xff0c;我将为大家介绍GitHub Copilot的配置和使用方法。GitHub Copilot基于OpenAI Codex模型&#xff0c;旨在为软件开发者提供智能化的代…

Android --- 在AIDL进程间通信中,为什么使用RemoteCallbackList 代替 ArrayList?

1.RemoteCallbackList vs ArrayList RemoteCallbackList 是一个特殊的 List&#xff0c;它用来管理跨进程的回调&#xff0c;特别是当回调对象是在不同进程中时。它在 AIDL&#xff08;Android Interface Definition Language&#xff09;通信中常常用来处理跨进程的通信。 Arr…

Prometheus 专栏 —— Prometheus入门介绍

Prometheus 是? Prometheus 是一个开源的服务监控系统和时序数据库&#xff0c;主要用于收集、存储、查询和告警时间序列数据&#xff0c;这些数据通常反映了系统或者应用的状态或性能 Prometheus 的基本功能是? 数据采集数据存储数据查询告警通知 Prometheus 监控核心组件?…

FIR数字滤波器设计——窗函数设计法——滤波器的时域截断

与IIR数字滤波器的设计类似&#xff0c;设计FIR数字滤波器也需要事先给出理想滤波器频率响应 H ideal ( e j ω ) H_{\text{ideal}}(e^{j\omega}) Hideal​(ejω)&#xff0c;用实际的频率响应 H ( e j ω ) H(e^{j\omega}) H(ejω)去逼近 H ideal ( e j ω ) H_{\text{ideal}}…

openssh9.9P1-CentOS7升级包

用于CentOS7.x系统的openssh版本升级&#xff0c;同时要求openssl版本为1.1.1w&#xff0c;SSL已经升级的只需要升级ssh即可。 处理方法 注意&#xff1a; 升级前&#xff0c;要确保root可以ssh登录或普通账号登录后能切换到root。将包里的文件上传至服务的/root目录下&#xf…

No Python at ‘C:\Users\MI\AppData\Local\Programs\Python\Python39\python.exe‘

目录 一、检查环境配置 1.1 安装键盘“winR”键并输入cmd 1.2 输入“python” 二、解决问题 2.1 检查本地的python配置路径 2.2 打开PyCharm的Settings 2.3 找到Python Interpreter 2.4 删除当前python版本 2.5 新添版本 PyCharm运行时出现的错误&#xff1a; No Py…

重温设计模式--6、享元模式

文章目录 享元模式&#xff08;Flyweight Pattern&#xff09;概述享元模式的结构C 代码示例1应用场景C示例代码2 享元模式&#xff08;Flyweight Pattern&#xff09;概述 定义&#xff1a; 运用共享技术有效地支持大量细粒度的对象。 享元模式是一种结构型设计模式&#xff0…

自动化办公-合并多个excel

在日常的办公自动化工作中&#xff0c;尤其是处理大量数据时&#xff0c;合并多个 Excel 表格是一个常见且繁琐的任务。幸运的是&#xff0c;借助 Python 语言中的强大库&#xff0c;我们可以轻松地自动化这个过程。本文将带你了解如何使用 Python 来合并多个 Excel 表格&#…