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号位。那用变长呢…...
springboot 百货中心供应链管理系统小程序
一、前言 随着我国经济迅速发展,人们对手机的需求越来越大,各种手机软件也都在被广泛应用,但是对于手机进行数据信息管理,对于手机的各种软件也是备受用户的喜爱,百货中心供应链管理系统被用户普遍使用,为方…...
微信小程序之bind和catch
这两个呢,都是绑定事件用的,具体使用有些小区别。 官方文档: 事件冒泡处理不同 bind:绑定的事件会向上冒泡,即触发当前组件的事件后,还会继续触发父组件的相同事件。例如,有一个子视图绑定了b…...
Debian系统简介
目录 Debian系统介绍 Debian版本介绍 Debian软件源介绍 软件包管理工具dpkg dpkg核心指令详解 安装软件包 卸载软件包 查询软件包状态 验证软件包完整性 手动处理依赖关系 dpkg vs apt Debian系统介绍 Debian 和 Ubuntu 都是基于 Debian内核 的 Linux 发行版ÿ…...
深入理解JavaScript设计模式之单例模式
目录 什么是单例模式为什么需要单例模式常见应用场景包括 单例模式实现透明单例模式实现不透明单例模式用代理实现单例模式javaScript中的单例模式使用命名空间使用闭包封装私有变量 惰性单例通用的惰性单例 结语 什么是单例模式 单例模式(Singleton Pattern&#…...
STM32F4基本定时器使用和原理详解
STM32F4基本定时器使用和原理详解 前言如何确定定时器挂载在哪条时钟线上配置及使用方法参数配置PrescalerCounter ModeCounter Periodauto-reload preloadTrigger Event Selection 中断配置生成的代码及使用方法初始化代码基本定时器触发DCA或者ADC的代码讲解中断代码定时启动…...
服务器硬防的应用场景都有哪些?
服务器硬防是指一种通过硬件设备层面的安全措施来防御服务器系统受到网络攻击的方式,避免服务器受到各种恶意攻击和网络威胁,那么,服务器硬防通常都会应用在哪些场景当中呢? 硬防服务器中一般会配备入侵检测系统和预防系统&#x…...
ffmpeg(四):滤镜命令
FFmpeg 的滤镜命令是用于音视频处理中的强大工具,可以完成剪裁、缩放、加水印、调色、合成、旋转、模糊、叠加字幕等复杂的操作。其核心语法格式一般如下: ffmpeg -i input.mp4 -vf "滤镜参数" output.mp4或者带音频滤镜: ffmpeg…...
ArcGIS Pro制作水平横向图例+多级标注
今天介绍下载ArcGIS Pro中如何设置水平横向图例。 之前我们介绍了ArcGIS的横向图例制作:ArcGIS横向、多列图例、顺序重排、符号居中、批量更改图例符号等等(ArcGIS出图图例8大技巧),那这次我们看看ArcGIS Pro如何更加快捷的操作。…...
AI书签管理工具开发全记录(十九):嵌入资源处理
1.前言 📝 在上一篇文章中,我们完成了书签的导入导出功能。本篇文章我们研究如何处理嵌入资源,方便后续将资源打包到一个可执行文件中。 2.embed介绍 🎯 Go 1.16 引入了革命性的 embed 包,彻底改变了静态资源管理的…...
安卓基础(aar)
重新设置java21的环境,临时设置 $env:JAVA_HOME "D:\Android Studio\jbr" 查看当前环境变量 JAVA_HOME 的值 echo $env:JAVA_HOME 构建ARR文件 ./gradlew :private-lib:assembleRelease 目录是这样的: MyApp/ ├── app/ …...
