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地址 域名的层级 根…...
微软PowerBI考试 PL300-在 Power BI 中清理、转换和加载数据
微软PowerBI考试 PL300-在 Power BI 中清理、转换和加载数据 Power Query 具有大量专门帮助您清理和准备数据以供分析的功能。 您将了解如何简化复杂模型、更改数据类型、重命名对象和透视数据。 您还将了解如何分析列,以便知晓哪些列包含有价值的数据,…...
【SSH疑难排查】轻松解决新版OpenSSH连接旧服务器的“no matching...“系列算法协商失败问题
【SSH疑难排查】轻松解决新版OpenSSH连接旧服务器的"no matching..."系列算法协商失败问题 摘要: 近期,在使用较新版本的OpenSSH客户端连接老旧SSH服务器时,会遇到 "no matching key exchange method found", "n…...
Chromium 136 编译指南 Windows篇:depot_tools 配置与源码获取(二)
引言 工欲善其事,必先利其器。在完成了 Visual Studio 2022 和 Windows SDK 的安装后,我们即将接触到 Chromium 开发生态中最核心的工具——depot_tools。这个由 Google 精心打造的工具集,就像是连接开发者与 Chromium 庞大代码库的智能桥梁…...
深度学习之模型压缩三驾马车:模型剪枝、模型量化、知识蒸馏
一、引言 在深度学习中,我们训练出的神经网络往往非常庞大(比如像 ResNet、YOLOv8、Vision Transformer),虽然精度很高,但“太重”了,运行起来很慢,占用内存大,不适合部署到手机、摄…...
【C++】纯虚函数类外可以写实现吗?
1. 答案 先说答案,可以。 2.代码测试 .h头文件 #include <iostream> #include <string>// 抽象基类 class AbstractBase { public:AbstractBase() default;virtual ~AbstractBase() default; // 默认析构函数public:virtual int PureVirtualFunct…...
LCTF液晶可调谐滤波器在多光谱相机捕捉无人机目标检测中的作用
中达瑞和自2005年成立以来,一直在光谱成像领域深度钻研和发展,始终致力于研发高性能、高可靠性的光谱成像相机,为科研院校提供更优的产品和服务。在《低空背景下无人机目标的光谱特征研究及目标检测应用》这篇论文中提到中达瑞和 LCTF 作为多…...
ubuntu系统文件误删(/lib/x86_64-linux-gnu/libc.so.6)修复方案 [成功解决]
报错信息:libc.so.6: cannot open shared object file: No such file or directory: #ls, ln, sudo...命令都不能用 error while loading shared libraries: libc.so.6: cannot open shared object file: No such file or directory重启后报错信息&…...
JDK 17 序列化是怎么回事
如何序列化?其实很简单,就是根据每个类型,用工厂类调用。逐个完成。 没什么漂亮的代码,只有有效、稳定的代码。 代码中调用toJson toJson 代码 mapper.writeValueAsString ObjectMapper DefaultSerializerProvider 一堆实…...
数据库正常,但后端收不到数据原因及解决
从代码和日志来看,后端SQL查询确实返回了数据,但最终user对象却为null。这表明查询结果没有正确映射到User对象上。 在前后端分离,并且ai辅助开发的时候,很容易出现前后端变量名不一致情况,还不报错,只是单…...
【阅读笔记】MemOS: 大语言模型内存增强生成操作系统
核心速览 研究背景 研究问题:这篇文章要解决的问题是当前大型语言模型(LLMs)在处理内存方面的局限性。LLMs虽然在语言感知和生成方面表现出色,但缺乏统一的、结构化的内存架构。现有的方法如检索增强生成(RA…...
