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

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地址 域名的层级 根…...

观成科技:隐蔽隧道工具Ligolo-ng加密流量分析

1.工具介绍 Ligolo-ng是一款由go编写的高效隧道工具,该工具基于TUN接口实现其功能,利用反向TCP/TLS连接建立一条隐蔽的通信信道,支持使用Let’s Encrypt自动生成证书。Ligolo-ng的通信隐蔽性体现在其支持多种连接方式,适应复杂网…...

反向工程与模型迁移:打造未来商品详情API的可持续创新体系

在电商行业蓬勃发展的当下,商品详情API作为连接电商平台与开发者、商家及用户的关键纽带,其重要性日益凸显。传统商品详情API主要聚焦于商品基本信息(如名称、价格、库存等)的获取与展示,已难以满足市场对个性化、智能…...

阿里云ACP云计算备考笔记 (5)——弹性伸缩

目录 第一章 概述 第二章 弹性伸缩简介 1、弹性伸缩 2、垂直伸缩 3、优势 4、应用场景 ① 无规律的业务量波动 ② 有规律的业务量波动 ③ 无明显业务量波动 ④ 混合型业务 ⑤ 消息通知 ⑥ 生命周期挂钩 ⑦ 自定义方式 ⑧ 滚的升级 5、使用限制 第三章 主要定义 …...

pam_env.so模块配置解析

在PAM(Pluggable Authentication Modules)配置中, /etc/pam.d/su 文件相关配置含义如下: 配置解析 auth required pam_env.so1. 字段分解 字段值说明模块类型auth认证类模块,负责验证用户身份&am…...

C# SqlSugar:依赖注入与仓储模式实践

C# SqlSugar:依赖注入与仓储模式实践 在 C# 的应用开发中,数据库操作是必不可少的环节。为了让数据访问层更加简洁、高效且易于维护,许多开发者会选择成熟的 ORM(对象关系映射)框架,SqlSugar 就是其中备受…...

QT: `long long` 类型转换为 `QString` 2025.6.5

在 Qt 中,将 long long 类型转换为 QString 可以通过以下两种常用方法实现: 方法 1:使用 QString::number() 直接调用 QString 的静态方法 number(),将数值转换为字符串: long long value 1234567890123456789LL; …...

在WSL2的Ubuntu镜像中安装Docker

Docker官网链接: https://docs.docker.com/engine/install/ubuntu/ 1、运行以下命令卸载所有冲突的软件包: for pkg in docker.io docker-doc docker-compose docker-compose-v2 podman-docker containerd runc; do sudo apt-get remove $pkg; done2、设置Docker…...

短视频矩阵系统文案创作功能开发实践,定制化开发

在短视频行业迅猛发展的当下,企业和个人创作者为了扩大影响力、提升传播效果,纷纷采用短视频矩阵运营策略,同时管理多个平台、多个账号的内容发布。然而,频繁的文案创作需求让运营者疲于应对,如何高效产出高质量文案成…...

【MATLAB代码】基于最大相关熵准则(MCC)的三维鲁棒卡尔曼滤波算法(MCC-KF),附源代码|订阅专栏后可直接查看

文章所述的代码实现了基于最大相关熵准则(MCC)的三维鲁棒卡尔曼滤波算法(MCC-KF),针对传感器观测数据中存在的脉冲型异常噪声问题,通过非线性加权机制提升滤波器的抗干扰能力。代码通过对比传统KF与MCC-KF在含异常值场景下的表现,验证了后者在状态估计鲁棒性方面的显著优…...

C语言中提供的第三方库之哈希表实现

一. 简介 前面一篇文章简单学习了C语言中第三方库(uthash库)提供对哈希表的操作,文章如下: C语言中提供的第三方库uthash常用接口-CSDN博客 本文简单学习一下第三方库 uthash库对哈希表的操作。 二. uthash库哈希表操作示例 u…...