GO - 泛型编程
go - 泛型编程
介绍
泛型即开发过程中编写适用于所有类型的模板,只有在具体使用的时候才能确定其真正的类型。随着Go 1.18版本的发布,泛型正式成为了Go语言的一部分。
在编写代码时,我们经常会遇到需要处理不同类型的数据的情况。传统上,我们需要为每种类型编写不同的函数或数据结构,这导致了代码的重复和冗余。而泛型编程可以解决这个问题,使得我们可以编写通用的代码,适用于多种类型的数据。
泛型作用
泛型编程有许多优势,包括提高代码的可读性、可维护性和可扩展性,减少代码的重复和冗余,以及增加代码的灵活性。然而,泛型编程也有一些局限性,包括可能引入额外的复杂性,增加编译时间,以及不适用于所有情况。
golang的泛型怎么使用
泛型函数
泛型函数是可以接受不同类型参数的函数。在定义泛型函数时,我们使用类型参数来代表参数类型,从而实现函数的通用性。
使用:在 Go 语言中,我们使用 func 关键字来定义函数,泛型函数的定义与普通函数类似,只是在函数名后面添加了类型参数的声明。泛型函数的类型参数可以是任意类型,通常使用大写字母开头的单个字母来表示。
特化:当我们调用泛型函数时,编译器会根据传入参数的类型特化生成相应的函数。例如,当我们将一个 []int 类型的切片传入 Print 函数时,编译器会生成一个专门用于处理 int 类型切片的函数;同样地,当传入一个 []string 类型的切片时,会生成一个专门用于处理 string 类型切片的函数。
package mainimport "fmt"func Print[T any](s []T) {for _, v := range s {fmt.Println(v)}
}func main() {s := []int{1, 2, 3, 4, 5}Print(s)s2 := []string{"hello", "world"}Print(s2)
}
泛型类型
泛型类型是一种可以适用于多种类型数据的数据结构或容器。与普通类型不同,泛型类型中的某些部分使用类型参数来代表任意类型的数据。通过使用类型参数,我们可以定义一次通用的数据结构或容器,而不必针对每种类型都编写单独的实现。
使用:在 Go 语言中,泛型类型通常通过在类型名称后面添加类型参数列表来定义。类型参数列表使用方括号括起来,并在其中声明一个或多个类型参数。
type Stack[T any] struct {elements []T
}
Stack 是一个泛型类型,它接受一个类型参数 T,表示栈中存储的元素类型。通过使用类型参数 T,我们可以定义一个通用的栈数据结构,使得栈可以存储任意类型的元素。
泛型类型的定义之后,我们可以使用具体的类型来实例化泛型类型。例如,我们可以使用 Stack[int] 来表示一个整数类型的栈,使用 Stack[string] 来表示一个字符串类型的栈,以此类推。
stack := Stack[int]{}
package mainimport "fmt"type Stack[T any] struct {elements []T
}func (s *Stack[T]) Push(e T) {s.elements = append(s.elements, e)
}func (s *Stack[T]) Pop() T {if len(s.elements) == 0 {return nil}e := s.elements[len(s.elements)-1]s.elements = s.elements[:len(s.elements)-1]return e
}func main() {stack := Stack[int]{}stack.Push(1)stack.Push(2)stack.Push(3)fmt.Println(stack.Pop()) // Output: 3fmt.Println(stack.Pop()) // Output: 2fmt.Println(stack.Pop()) // Output: 1
}
泛型接口
泛型接口是一种可以接受任意类型参数的接口,它们使用类型参数来代表任意类型的数据。通过使用类型参数,我们可以定义一次通用的接口,而不必针对每种类型都编写单独的接口。这样,我们就能够针对不同类型的数据实现相同的接口方法,实现了对不同类型数据的通用操作。
使用 :泛型接口通常通过在接口名称后面添加类型参数列表来定义。类型参数列表使用方括号括起来,并在其中声明一个或多个类型参数。
type Container[T any] interface {Add(T)Remove() T
}
Container 是一个泛型接口,它接受一个类型参数 T,表示容器中存储的元素类型。通过使用类型参数 T,我们可以定义一个通用的容器接口,使得容器可以存储任意类型的元素,并且具有相同的添加和移除元素的方法。
泛型接口的定义之后,我们可以使用具体的类型来实现泛型接口。例如,我们可以针对不同类型的数据分别实现 Container 接口的方法:
type Queue[T any] struct {elements []T
}func (q *Queue[T]) Add(e T) {q.elements = append(q.elements, e)
}func (q *Queue[T]) Remove() T {if len(q.elements) == 0 {return nil}e := q.elements[0]q.elements = q.elements[1:]return e
}
我们针对不同类型的数据实现了 Container 接口的方法,分别用于实现一个泛型队列数据结构。通过实现泛型接口,我们可以实现对不同类型数据的通用操作,提高了代码的复用性和灵活性。
泛型结构体
泛型结构体是一种可以适用于多种类型数据的结构体,它们使用类型参数来代表任意类型的数据。通过使用类型参数,我们可以定义一次通用的结构体,而不必针对每种类型都编写单独的结构体。这样,我们就能够定义一个通用的数据结构,用于存储任意类型的数据。
使用:泛型结构体通常通过在结构体名称后面添加类型参数列表来定义。类型参数列表使用方括号括起来,并在其中声明一个或多个类型参数。例如:
type Pair[T any] struct {First TSecond T
}
Pair 是一个泛型结构体,它接受一个类型参数 T,表示结构体中存储的元素类型。通过使用类型参数 T,我们可以定义一个通用的结构体,使得结构体中的字段可以存储任意类型的数据,并且具有相同的结构。
泛型结构体的定义之后,我们可以使用具体的类型来实例化泛型结构体。例如:
pair1 := Pair[int]{First: 1, Second: 2}
pair2 := Pair[string]{First: "hello", Second: "world"}
在上面的示例中,我们分别使用 Pair[int] 和 Pair[string] 来实例化了两个不同类型的泛型结构体。通过实例化泛型结构体,我们可以创建不同类型的数据结构,用于存储不同类型的数据。
泛型receiver
泛型 receiver 是指在方法定义中使用类型参数来表示接收者类型的一种方式。通过使用类型参数,可以使得方法适用于多种类型的接收者,从而实现对不同类型的数据的通用操作。
使用:在 Go 语言中,可以在方法定义中使用类型参数来表示接收者类型。例如:
type Stack[T any] struct {elements []T
}func (s *Stack[T]) Push(e T) {s.elements = append(s.elements, e)
}func (s *Stack[T]) Pop() T {if len(s.elements) == 0 {return nil}e := s.elements[len(s.elements)-1]s.elements = s.elements[:len(s.elements)-1]return e
}
Stack 结构体定义了一个泛型的栈数据结构,然后在方法定义中使用类型参数 T 来表示接收者类型。这样,Push 和 Pop 方法就可以适用于不同类型的栈,而不必针对每种类型都编写单独的方法。
下面是一个使用泛型 receiver 的示例,用于实现一个泛型栈数据结构:
package mainimport "fmt"type Stack[T any] struct {elements []T
}func (s *Stack[T]) Push(e T) {s.elements = append(s.elements, e)
}func (s *Stack[T]) Pop() T {if len(s.elements) == 0 {return nil}e := s.elements[len(s.elements)-1]s.elements = s.elements[:len(s.elements)-1]return e
}func main() {stack := Stack[int]{}stack.Push(1)stack.Push(2)stack.Push(3)fmt.Println(stack.Pop()) // Output: 3fmt.Println(stack.Pop()) // Output: 2fmt.Println(stack.Pop()) // Output: 1
}
泛型限制
匿名结构体与匿名函数不支持泛型
目前在 Go 语言中,匿名结构体和匿名函数不支持泛型。这意味着无法在匿名结构体或匿名函数中使用类型参数。
不支持类型断言
类型断言是一种在 Go 中用于判断接口值的实际类型的机制。然而,目前的泛型实现不支持类型断言。因此,在泛型代码中无法使用类型断言来判断类型。
不支持泛型方法,只能通过receiver来实现方法的泛型处理
目前,Go 语言的泛型实现中不支持直接在方法中使用类型参数。虽然可以通过在方法定义中使用类型参数来表示接收者类型(即泛型 receiver),但是不能直接在方法体内部使用类型参数。
~后的类型必须为基本类型,不能为接口类型
在使用泛型类型参数时,其类型必须为基本类型,不能为接口类型。这意味着类型参数不能用于定义接口类型,而只能用于定义基本类型的变量或参数。
相关文章:
GO - 泛型编程
go - 泛型编程 介绍 泛型即开发过程中编写适用于所有类型的模板,只有在具体使用的时候才能确定其真正的类型。随着Go 1.18版本的发布,泛型正式成为了Go语言的一部分。 在编写代码时,我们经常会遇到需要处理不同类型的数据的情况。传统上&am…...
TouchableOpacity和TouchableWithoutFeedback区别
TouchableOpacity和TouchableWithoutFeedback都是React Native中定义的可触摸组件,但它们之间有一些区别: 点击效果:TouchableOpacity在被按下时会有一个透明度变化的点击效果,而TouchableWithoutFeedback则没有点击效果。 子组…...
MySQL EXISTS 语句和IN语句有啥区别
在 MySQL 中,EXISTS 和 IN 是用于子查询的两种不同方式,它们有一些区别: 1. **IN 语句**: - IN 子句用于在 WHERE 子句中指定多个值,并检查主查询中的某个列是否在子查询返回的结果集中。 - IN 子句适用于子查询…...
Java集合体系面试题
1. Java中有哪些主要的集合接口? 答案:Java中主要的集合接口有Collection、List、Set、Queue和Map。 2. 请解释List和Set之间的主要区别。 答案:List和Set的主要区别在于元素的顺序和唯一性。List是有序的集合,允许存储重复的元…...
React-2-useState-获取DOM-组件通信
一.useState useState 是一个 React Hook(函数),它允许我们向组件添加一个状态变量, 从而控制影响组件的渲染结果 本质:和普通JS变量不同的是,状态变量一旦发生变化组件的视图UI也会跟着变化**(数据驱动视…...

使用nodejs搭建脚手架工具并发布到npm中
使用nodejs搭建脚手架工具并发布到npm中 一、安装环境依赖及脚手架搭建过程二、搭建Monorepo 风格的脚手架工程三、脚手架的必备模块命令参数模块获取命令参数设置子命令用户交互模块文件拷贝模块脚手架中的路径处理目录守卫文件拷贝模块动态文件生成模块mustache简介自动安装依…...
【面经】3月29日 美团/美团平台/后端/一面/1h
面试官先介绍自己部门的业务:存储中心,涉及到大量数据的离线处理(亿级别)。 手撕(删除链表倒数第k个节点) 自我介绍 项目介绍(还没说完被打断了,面试官说你这个感觉就是把功能说了一…...
CSS:CSS的基础了解
css概述 CSS(Cascading Style Sheets,层叠样式表) 是用于控制网页样式和布局的一种样式表语言。用于描述网页的样式和布局,包括字体、颜色、大小、间距、边框等方面。 前端三🗡客:HTML,CSS,JavaScript&am…...

Android Framework学习笔记(2)----系统启动
Android系统的启动流程 启动过程中,用户可控部分是framework的init流程。init是系统中的第一个进程,其它进程都是它的子进程。 启动逻辑源码参照:system/core/init/main.cpp 关键调用顺序:main->FirstStageMain->SetupSel…...
项目管理中的估算活动资源
在项目管理中,资源估算是一项至关重要的任务。正确地估算活动资源可以确保项目的顺利进行,避免资源浪费和不必要的延误。以下是对项目管理中常见的活动资源类型的详细分析。 一、人力资源 人力资源是项目管理中最基本的资源之一。它包括项目团队成员的技能、知识和经验。在…...
java中的set集合及其子类
Set系列集合:添加的元素是无序(添加的数据的顺序和获取出数据顺序不一样),不重复,无索引 如:HashSet:无序,不可重复,无索引 LinkedHashSet:有序,不重复,无索…...
shell脚本查询匹配文件进行操作
1.寻找文件并赋权 查询当前目录及子目录下所有以“sh”结尾的文件,并赋执行权限。 #!/bin/bash # 将当前目录及子目录下所有以“sh”结尾的文件添加可执行权限 find ./ -name "*.sh" -type f -exec chmod x {} 2.寻找文件并删除 查询当前目录及子目录下存…...

vulnhub----natraj靶机
文章目录 一.信息收集1.网段探测2.端口扫描3.版本服务探测4.漏扫5.目录扫描 二.漏洞利用1.分析信息2..fuzz工具 三.getshell四.提权六.nmap提权 一.信息收集 1.网段探测 因为使用的是VMware,靶机的IP地址是192.168.9.84 ┌──(root㉿kali)-[~/kali/vulnhub] └─…...

Web Component 组件库有什么优势
前言 前端目前比较主流的框架有 react,vuejs,angular 等。 我们通常去搭建组件库的时候都是基于某一种框架去搭建,比如 ant-design 是基于 react 搭建的UI组件库,而 element-plus 则是基于 vuejs 搭建的组件库。 可能你有这种体…...

如何配置vite的proxy
1.前言 vite项目,本地开发环境可以通过配置proxy代理实现跨域请求。但是生产环境,该配置不生效,一般使用 nginx 转发,或者后端配置cors 2.解释 server: {port: 9000,proxy: { // 本地开发环境通过代理实现跨域,生产…...
Linux CentOS基础操作
Linux CentOS基础操作 1. 查看Linux服务器当前主机名等 hostname 2. 查看当前系统日期和时间 date -d -y 3. 显示网络接口信息,获取当前网卡状态,启动、停止网卡,网卡等闪烁显示30秒,配置网卡(网卡名称:eth1)的IP地址…...
最佳情侣身高差
题目描述 专家通过多组情侣研究数据发现,最佳的情侣身高差遵循着一个公式:(女方的身高)1.09 (男方的身高)。如果符合,你俩的身高差不管是牵手、拥抱、接吻,都是最和谐的差度。 下面…...
谷歌开发者账号防关联:如何选择性价比高的VPS,阿里、腾讯、酷鸟、AWS?
在Google Play上架应用的开发者朋友们,可能需要多个开发者账号来上架马甲包或矩阵式上架应用。但谷歌那边又不让一个人搞多个账号,所以,要想不被谷歌抓包,就得做好防关联的功课,确保每个账号都像是独立的个体。 而说到…...
Virtual digital asset $E=$eaco. EarthChain
Virtual digital asset $E$eaco. EarthChain Виртуальный цифровой актив $E $eaco. Цепочка Земля. 仮想デジタル資産$E$eaco.アースチェーン. Activos digitales virtuales $e $oaco. cadena terrestre. Virtuelles digitales Asset $E…...

[计算机网络] 当输入网址到网页
HTTP 首先,对URL进行解析,URL包含了Web服务器和对应的文件(文件路径) URL是请求服务器中的文件资源 通过Web服务器和对应文件来生产HTTP包(超文本传输协议) DNS 根据域名查询对应的IP地址 域名的层级 根…...

网络编程(Modbus进阶)
思维导图 Modbus RTU(先学一点理论) 概念 Modbus RTU 是工业自动化领域 最广泛应用的串行通信协议,由 Modicon 公司(现施耐德电气)于 1979 年推出。它以 高效率、强健性、易实现的特点成为工业控制系统的通信标准。 包…...
零门槛NAS搭建:WinNAS如何让普通电脑秒变私有云?
一、核心优势:专为Windows用户设计的极简NAS WinNAS由深圳耘想存储科技开发,是一款收费低廉但功能全面的Windows NAS工具,主打“无学习成本部署” 。与其他NAS软件相比,其优势在于: 无需硬件改造:将任意W…...
基于Uniapp开发HarmonyOS 5.0旅游应用技术实践
一、技术选型背景 1.跨平台优势 Uniapp采用Vue.js框架,支持"一次开发,多端部署",可同步生成HarmonyOS、iOS、Android等多平台应用。 2.鸿蒙特性融合 HarmonyOS 5.0的分布式能力与原子化服务,为旅游应用带来…...

C# 类和继承(抽象类)
抽象类 抽象类是指设计为被继承的类。抽象类只能被用作其他类的基类。 不能创建抽象类的实例。抽象类使用abstract修饰符声明。 抽象类可以包含抽象成员或普通的非抽象成员。抽象类的成员可以是抽象成员和普通带 实现的成员的任意组合。抽象类自己可以派生自另一个抽象类。例…...

Springboot社区养老保险系统小程序
一、前言 随着我国经济迅速发展,人们对手机的需求越来越大,各种手机软件也都在被广泛应用,但是对于手机进行数据信息管理,对于手机的各种软件也是备受用户的喜爱,社区养老保险系统小程序被用户普遍使用,为方…...

2025季度云服务器排行榜
在全球云服务器市场,各厂商的排名和地位并非一成不变,而是由其独特的优势、战略布局和市场适应性共同决定的。以下是根据2025年市场趋势,对主要云服务器厂商在排行榜中占据重要位置的原因和优势进行深度分析: 一、全球“三巨头”…...
《C++ 模板》
目录 函数模板 类模板 非类型模板参数 模板特化 函数模板特化 类模板的特化 模板,就像一个模具,里面可以将不同类型的材料做成一个形状,其分为函数模板和类模板。 函数模板 函数模板可以简化函数重载的代码。格式:templa…...
A2A JS SDK 完整教程:快速入门指南
目录 什么是 A2A JS SDK?A2A JS 安装与设置A2A JS 核心概念创建你的第一个 A2A JS 代理A2A JS 服务端开发A2A JS 客户端使用A2A JS 高级特性A2A JS 最佳实践A2A JS 故障排除 什么是 A2A JS SDK? A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库ÿ…...

uniapp 小程序 学习(一)
利用Hbuilder 创建项目 运行到内置浏览器看效果 下载微信小程序 安装到Hbuilder 下载地址 :开发者工具默认安装 设置服务端口号 在Hbuilder中设置微信小程序 配置 找到运行设置,将微信开发者工具放入到Hbuilder中, 打开后出现 如下 bug 解…...

数据结构:递归的种类(Types of Recursion)
目录 尾递归(Tail Recursion) 什么是 Loop(循环)? 复杂度分析 头递归(Head Recursion) 树形递归(Tree Recursion) 线性递归(Linear Recursion)…...