Golang1.18新特性介绍——泛型
社区长期高呼的泛型特性在Golang 1.18中终于正式发布,Go泛型实现与传统的C++有较大差异,更像Rust的泛型实现。本文详细介绍Golang泛型及其特性,包括泛型语法、类型参数、类型约束、类型近似以及constraints包提供内置类型等。
最近写Dao代码,利用泛型可让代码更简洁通用。为了更系统掌握,特整理了Go泛型相关内容。
泛型概述
泛型可以让更通用,无需给参数或返回值显示指定特定类型,如,写函数或结构体时,无需具体指定值的类型。具体值类型之后传入,从而避免大量冗余模板代码。
泛型的目标就是消除模板代码。举例:反转数组函数无需知道数组元素类型,但如果不采用泛型则不能保障类型安全,或给每个具体类型重试实现同样逻辑,增加维护成本。
泛型语法
Go1.18.0 引入新的语法支持类型元数据并定义类型约束。举例:
func main() {fmt.Println(reverse([]int{1, 2, 3, 4, 5}))
}// T 是类型参数,在函数体内像正常类型一样使用
// any 是类型约束,后面会介绍其他类型
func reverse[T any](s []T) []T {l := len(s)r := make([]T, l)for i, ele := range s {r[l-i-1] = ele}return r
}
函数名后[]
用于指定类型参数, 可以包括一组类型标识以及约束类型。这里T是类型参数,可用于函数参数和返回值类型。any是interface的别名,其定义为:type any = interface{}
。
定义好泛型函数后,调用时直接传入具体类型。我们也可以实例化泛型函数,然后再调用:
func main() {// fmt.Println(reverse([]int{1, 2, 3, 4, 5}))// 实例化泛型函数reverseInt := reverse[int]// 使用reverseInt进行调用reverseInt([]int{1, 2, 3, 4, 5})}
前面的调用方式,Golang编译器自动推断泛型类型,所以下面两种方式结果一致:
// 未传入类型
fmt.Println(reverse([]int{1, 2, 3, 4, 5}))// 传入类型
fmt.Println(reverse[int]([]int{1, 2, 3, 4, 5}))
类型参数
基于具体类型的实用函数实用泛型让代码更通用,下面看一些具体示例,包括Slice,Map,当然Channel也支持泛型:
- Slice
// 泛型slice ForEach函数, 对每个元素执行一个特定函数.
// 通过实用泛型,使得ForEach功能更通用,适合更多类型.
func ForEach[T any](s []T, f func(ele T, i int , s []T)){
for i,ele := range s {
f(ele,i,s)
}
}
- Mapmap需要两个类型,key和value类型,下面示例value没有限制,key需要满足comparable限制:
// keys 返回mapkey集合
// 这里 m 使用K 和 V作为泛型
// V 的约束为 any
// K的约束为 comparable,可以理解为任何支持 != 和 == 操作的类型,后面会讲解约束
func keys[K comparable, V any](m map[K]V) []K {
// 使用K类型和map长度创建分片
key := make([]K, len(m))
i := 0
for k, _ := range m {
key[i] = k
i++
}
return key
}
- 结构体类型参数Go也支持使用类型参数定义struct。语法和函数类似,可以在struct的数据成员和方法上使用类型参数。
// T is type parameter here, with any constraint
type MyStruct[T any] struct {
inner T
}
// No new type parameter is allowed in struct methods
func (m *MyStruct[T]) Get() T {
return m.inner
}
func (m *MyStruct[T]) Set(v T) {
m.inner = v
}
方法仅能使用struct中定义的类型参数,不能使用新的类型参数。- 嵌套类型参数泛型类型可以嵌套在其他类型中,定义在函数或结构体的类型参数可传给任何其他带类型参数的类型。举例:
// Generic struct with two generic types
type Enteries[K, V any] struct {
Key K
Value V
}
// map需要key可比较,K声明为comparable约束
// 这里使用了嵌套参数类型
// 初始化Enteries[K,V] 作为返回值类型,它使用K,V作为参数
func enteries[K comparable, V any](m map[K]V) []*Enteries[K, V] {
// define a slice with Enteries type passing K, V type parameters
e := make([]*Enteries[K, V], len(m))
i := 0
for k, v := range m {
// 使用new关键字创建变量
newEntery := new(Enteries[K, V])
newEntery.Key = k
newEntery.Value = v
e[i] = newEntery
i++
}
return e
}
这里Enteries类型作为enteries函数的返回值,通过传入需要的类型被实例化。## 类型约束与C++不同,Go泛型仅允许执行interface内列举的操作,这里interface称为约束。编译器使用约束来确保为使用类型参数实例化值执行的所有操作在一定类型范围内。举例,下面代码片段中,T仅支持string方法,如len()或其他字符串方法。
// Stringer is a constraint
type Stringer interface {
String() string
}
// Here T has to implement Stringer, T can only perform operations defined by Stringer
func stringer[T Stringer](s T) string {
return s.String()
}
## 预定类型作为约束Go的新功能允许预定义类型(如int和string)实现约束中使用的interface。这些具有预定义类型的interface只能用作约束。
type Number {
int
}
不能在方法上使用这些预定义类型,因为预定义类型在这些已定义类型上没有方法。
type Number {
int
Name()string // int don’t have Name method
}
`|`操作可以定义联合类型,即定义多个具体类型作为预定义类型;
type Number interface {
int | int8 | int16 | int32 | int64 | float32 | float64
}
上面示例中,Number类型支持所有能够执行如` <,> +,-`算术操作的类型。可以使用联合类型作为约束,定义泛型函数:
// T 是类型参数,支持上述联合类型的一种
// 具体联合类型参数应该能实现算术运算操作
func Min[T Number](x, y T) T {
if x < y {
return x
}
return y
}
## 近似类型Go支持从预定义类型(如int,string)创建用户定义类型, `~` 操作符指定interface支持与底层相同的类型。举例,Point类型底层为int类型,则Number定义需要使用`~`操作符.
// Any Type with given underlying type will be supported by this interface
type Number interface {
~int | ~int8 | ~int16 | ~int32 | ~int64 | ~float32 | ~float64
}
// Type with underlying int
type Point int
func Min[T Number](x, y T) T {
if x < y {
return x
}
return y
}
func main() {
// creating Point type
x, y := Point(5), Point(2)
fmt.Println(Min(x, y))
}
也可以不声明直接使用近似类型作为类型参数:
// Union operator and type approximation both use together without interface
func Min[T ~int | ~float32 | ~float64](x, y T) T {
if x < y {
return x
}
return y
}
约束也支持嵌套,Number约束嵌套使用Float约束:
// Float is made up of all the float type
type Float interface {
~float32 | ~float64
}
// Number is build from Integer and Float
type Number interface {
Integer | Float
}
// Using Number
func Min[T Number](x, y T) T {
if x < y {
return x
}
return y
}
## constraints 包constraints包暴露一些预定义约束类型,既然已经内置了约束类型,最好直接使用。其中最重要的是[Ordered](https://pkg.go.dev/golang.org/x/exp/constraints#Ordered)约束,所有支持`>,<,==, !=` 操作的类型。
func min[T constraints.Ordered](x, y T) T {
if x > y {
return x
} else {
return y
}
}
## 总结interface表示实现该interface的一组类型,泛型不是interface的替代,泛型是基于interface设计的,为了提升Go类型安全,同时消除代码重复。泛型是实际类型的占位符,在编译期间泛型代码可能会转换为基于interface的具体实现。本文介绍了如定义类型参数,以及如何和函数和结构体一起使用类型参数实现泛型。同时也介绍了联合类型和近似类型,最后还提及了contraints包内置的类型。参考内容:https://blog.logrocket.com/understanding-generics-go-1-18/, 以及官方文档。
相关文章:
Golang1.18新特性介绍——泛型
社区长期高呼的泛型特性在Golang 1.18中终于正式发布,Go泛型实现与传统的C有较大差异,更像Rust的泛型实现。本文详细介绍Golang泛型及其特性,包括泛型语法、类型参数、类型约束、类型近似以及constraints包提供内置类型等。 最近写Dao代码&am…...

【SpringBoot17】SpringBoot中使用Quartz管理定时任务
定时任务在系统中用到的地方很多,例如每晚凌晨的数据备份,每小时获取第三方平台的 Token 信息等等,之前我们都是在项目中规定这个定时任务什么时候启动,到时间了便会自己启动,那么我们想要停止这个定时任务的时候&…...

杨辉三角形 (蓝桥杯) JAVA
目录题目描述:暴力破解(四成):二分法破解(满分):题目描述: 下面的图形是著名的杨辉三角形: 如果我们按从上到下、从左到右的顺序把所有数排成一列,可以得到如…...

AI制药 - AlphaFold Multimer 的 MSA Pairing 源码
目前最新版本是v2.3.1,2023.1.12 AlphaFold multimer v1 于 2021 年 7 月发布,同时发表了一篇描述其方法和结果的论文。AlphaFold multimer v1 使用了与 AlphaFold 单体相同的模型结构和训练方法,但增加了一些特征和损失函数来处理多条链。Al…...

TitanIDE:云原生开发到底强在哪里?
原文作者:行云创新技术总监 邓冰寒 引言 是一种新的软件开发方法,旨在构建更可靠、高效、弹性、安全和可扩展的应用程序。与传统的应用程序开发方式不同,云原生是将开发环境完全搬到云端,构建一站式的云原生开发环境。云原生的开…...
单片机常用完整性校验算法
一、前言 单片机在开发过程中经常会遇到大文件传输,或者大量数据传输,在一些工业环境下,数据传输并不是很稳定,如何检验数据的完整性就是个问题,这里简单介绍一下单片机常用的几种数据完整性校验方法。 二、CheckSum校…...

Anaconda 的安装配置及依赖项的内外网配置
在分享anaconda 的安装配置及使用前,我们必须先明白anaconda是什么;Anaconda是一个开源的Python发行版本。两者区别在于前者是一门编程语言,后者相当于编程语言中的工具包。 由于python自身缺少numpy、matplotlib、scipy、scikit-learn等一系…...

p84 CTF夺旗-PHP弱类型异或取反序列化RCE
数据来源 文章参考 本课重点: 案例1:PHP-相关总结知识点-后期复现案例2:PHP-弱类型对比绕过测试-常考点案例3:PHP-正则preg_match绕过-常考点案例4:PHP-命令执行RCE变异绕过-常考点案例5:PHP-反序列化考题…...

2022财报逆转,有赞穿透迷雾实现突破
2022年,商家经营面临困难。但在一些第三方服务商的帮助下,也有商家取得了逆势增长。 2023年3月23日,有赞发布2022年业绩报告,它帮助许多商家稳住了一整年的经营。2022年,有赞门店SaaS业务的GMV达到425亿元,…...

蓝桥杯 - 求组合数【C(a,b)】+ 卡特兰数
文章目录💬前言885. 求组合数 I C(m,n) 【dp】886 求组合数 II 【数据大小10万级别】 【费马小定理快速幂逆元】887. 求组合数 III 【le18级别】 【卢卡斯定理 逆元 快速幂 】888.求组合数 IV 【没有%p -- 高精度算出准确结果】 【分解质因数 高精度乘法 --只用一…...

膳食真菌在癌症免疫治疗中的作用: 从肠道微生物群的角度
谷禾健康 癌症是一种恶性肿瘤,它可以发生在人体的任何部位,包括肺、乳房、结肠、胃、肝、宫颈等。根据世界卫生组织的数据,全球每年有超过1800万人被诊断出患有癌症,其中约有1000万人死于癌症。癌症已成为全球范围内的主要健康问题…...
怎么将模糊的照片变清晰
怎么将模糊的照片变清晰?珍贵的照片每个人都会有,而遇到珍贵的照片变模糊了,相信会让人很苦恼的。那么有没有办法可以解决呢?答案是有的,我们可以用工具让模糊的照片变得清晰。下面就来分享一些让模糊的照片变清晰的方法,有兴趣…...

【软件测试】基础知识第一篇
文章目录一. 什么是软件测试二. 测试和调试的区别三. 什么是测试用例四. 软件的生命周期五. 软件测试的生命周期一. 什么是软件测试 软件测试就是验证软件产品特性是否满足用户的需求。 那需求又是什么呢?在多数软件公司,会有两种需求,一种…...

【百面成神】java web基础7问,你能坚持到第几问
前 言 🍉 作者简介:半旧518,长跑型选手,立志坚持写10年博客,专注于java后端 ☕专栏简介:纯手打总结面试题,自用备用 🌰 文章简介:java web最基础、重要的8道面试题 文章目…...

Centos7安装、各种环境配置和常见bug解决方案,保姆级教程(更新中)
文章目录前言一、Centos7安装二、各种环境配置与安装2.1 安装net-tools(建议)2.2 配置静态网络(建议)2.1 修改Centos7的时间(建议)2.2 Centos7系统编码问题2.3 vim安装(建议)2.4 解决…...

【C++进阶】智能指针
文章目录为什么需要智能指针?内存泄漏什么是内存泄漏,内存泄漏的危害内存泄漏分类(了解)如何避免内存泄漏智能指针的使用及原理smart_ptrauto_ptrunique_ptrshared_ptr线程安全的解决循环引用weak_ptr删除器为什么需要智能指针&am…...

软件测试面试题 —— 整理与解析(3)
😏作者简介:博主是一位测试管理者,同时也是一名对外企业兼职讲师。 📡主页地址:🌎【Austin_zhai】🌏 🙆目的与景愿:旨在于能帮助更多的测试行业人员提升软硬技能…...
springboot常用的20个注解
Spring Boot方式的项目开发已经逐步成为Java应用开发领域的主流框架,它不仅可以方便地创建生产级的Spring应用程序,还能轻松地通过一些注解配置与目前比较火热的微服务框架SpringCloud集成, 而Spring Boot 之所以能够轻松地实现应的创建及与…...
USB组合设备——带鼠标功能的键盘
文章目录带鼠标功能的键盘一个接口实现报告描述符示例多个接口实现复合设备和组合设备配置描述符集合的实现报告的返回附 STM32 枚举日志复合设备:Compound Device 内嵌 Hub 和多个 Function,每个 Function 都相当于一个独立的 USB 外设,有自…...

数据结构与算法基础-学习-18-哈夫曼编码
一、个人理解在远程通讯中,需要把字符转成二进制的字符串进行传输,例如我们需要传输ABCD,我们可以用定长的字符串进行表示,例如:A:00B:01C:02D:03这样可能就造成空间的浪费,我们多存储了一个0号位。那用变长呢…...
oracle与MySQL数据库之间数据同步的技术要点
Oracle与MySQL数据库之间的数据同步是一个涉及多个技术要点的复杂任务。由于Oracle和MySQL的架构差异,它们的数据同步要求既要保持数据的准确性和一致性,又要处理好性能问题。以下是一些主要的技术要点: 数据结构差异 数据类型差异ÿ…...
LLM基础1_语言模型如何处理文本
基于GitHub项目:https://github.com/datawhalechina/llms-from-scratch-cn 工具介绍 tiktoken:OpenAI开发的专业"分词器" torch:Facebook开发的强力计算引擎,相当于超级计算器 理解词嵌入:给词语画"…...

【C++特殊工具与技术】优化内存分配(一):C++中的内存分配
目录 一、C 内存的基本概念 1.1 内存的物理与逻辑结构 1.2 C 程序的内存区域划分 二、栈内存分配 2.1 栈内存的特点 2.2 栈内存分配示例 三、堆内存分配 3.1 new和delete操作符 4.2 内存泄漏与悬空指针问题 4.3 new和delete的重载 四、智能指针…...
C++课设:简易日历程序(支持传统节假日 + 二十四节气 + 个人纪念日管理)
名人说:路漫漫其修远兮,吾将上下而求索。—— 屈原《离骚》 创作者:Code_流苏(CSDN)(一个喜欢古诗词和编程的Coder😊) 专栏介绍:《编程项目实战》 目录 一、为什么要开发一个日历程序?1. 深入理解时间算法2. 练习面向对象设计3. 学习数据结构应用二、核心算法深度解析…...
【Android】Android 开发 ADB 常用指令
查看当前连接的设备 adb devices 连接设备 adb connect 设备IP 断开已连接的设备 adb disconnect 设备IP 安装应用 adb install 安装包的路径 卸载应用 adb uninstall 应用包名 查看已安装的应用包名 adb shell pm list packages 查看已安装的第三方应用包名 adb shell pm list…...
提升移动端网页调试效率:WebDebugX 与常见工具组合实践
在日常移动端开发中,网页调试始终是一个高频但又极具挑战的环节。尤其在面对 iOS 与 Android 的混合技术栈、各种设备差异化行为时,开发者迫切需要一套高效、可靠且跨平台的调试方案。过去,我们或多或少使用过 Chrome DevTools、Remote Debug…...

[拓扑优化] 1.概述
常见的拓扑优化方法有:均匀化法、变密度法、渐进结构优化法、水平集法、移动可变形组件法等。 常见的数值计算方法有:有限元法、有限差分法、边界元法、离散元法、无网格法、扩展有限元法、等几何分析等。 将上述数值计算方法与拓扑优化方法结合&#…...
StarRocks 全面向量化执行引擎深度解析
StarRocks 全面向量化执行引擎深度解析 StarRocks 的向量化执行引擎是其高性能的核心设计,相比传统行式处理引擎(如MySQL),性能可提升 5-10倍。以下是分层拆解: 1. 向量化 vs 传统行式处理 维度行式处理向量化处理数…...
【Java】Ajax 技术详解
文章目录 1. Filter 过滤器1.1 Filter 概述1.2 Filter 快速入门开发步骤:1.3 Filter 执行流程1.4 Filter 拦截路径配置1.5 过滤器链2. Listener 监听器2.1 Listener 概述2.2 ServletContextListener3. Ajax 技术3.1 Ajax 概述3.2 Ajax 快速入门服务端实现:客户端实现:4. Axi…...

python可视化:俄乌战争时间线关键节点与深层原因
俄乌战争时间线可视化分析:关键节点与深层原因 俄乌战争是21世纪欧洲最具影响力的地缘政治冲突之一,自2022年2月爆发以来已持续超过3年。 本文将通过Python可视化工具,系统分析这场战争的时间线、关键节点及其背后的深层原因,全面…...