GO基础进阶篇 (十三)、泛型

泛型

先看一下这段代码。

package mainimport "fmt"func main() {strs := []string{"a", "b"}printArray(strs)
}func printArray(arr []interface{}) {for _, a := range arr {fmt.Println(a)}
}

上面的代码中,我们想要打印参数arr的信息。运行报错

 cannot use strs (variable of type []string) as []interface{} value in argument to printArray

想要解决的话,按照之前我们的学习,可以将函数改编如下(使用断言)

package mainimport "fmt"func main() {strs := []string{"a", "b"}printStringArray(strs)
}func printStringArray(arr interface{}) {for _, a := range arr.([]string) {fmt.Println(a)}
}

但这样会有一个坏处,当我们想要打印另一个非string的数组时,就不得不再写一个方法

package mainimport "fmt"func main() {ints := []int{1, 2}printIntArray(ints)
}func printIntArray(arr interface{}) {for _, a := range arr.([]int) {fmt.Println(a)}
}

这样处理,就会导致有无限多相似的代码产生,这样的代码时不合格的。

此时,泛型就出现了。它的意义时不在方法定义时决定变量的类型,而让使用者使用时决定。

package mainimport "fmt"func main() {ints := []int{1, 2}strs := []string{"a", "b"}printArray(ints)printArray(strs)
}func printArray[T string | int](arr []T) {for _, a := range arr {fmt.Println(a)}
}

T代表了用户传入的类型,并对T进行了约束。上面的代码中,我们再定一个float的数组,是无法通过程序校验的,因为我们约束了T的可用类型为stirng与int。

使用泛型,你可能会产生一个疑惑,通过我们刚刚学习的反射,再加上接口。也可以类似泛型这样的函数。这样是可行的,但反射的机制存在一些问题

  • 1.用起来麻烦
  • 2.失去了编译时的类型检查,容易出错
  • 3.性能不理想

结论:当需要因为不同类型写完全相同的逻辑代码时,使用泛型时最合适的选择。

泛型类型

  • 泛型切片
package mainimport "fmt"func main() {type Slice[T int | string | float32] []Tvar a Slice[int] = []int{1, 2, 3}var b Slice[string] = []string{"a", "b", "c"}var c Slice[float32] = []float32{1, 2, 3}fmt.Printf("%T", a)fmt.Println(a)fmt.Printf("%T", b)fmt.Println(b)fmt.Printf("%T", c)fmt.Println(c)
}//main.Slice[int][1 2 3]
//main.Slice[string][a b c]
//main.Slice[float32][1 2 3]
  • 泛型map
package mainimport "fmt"func main() {type MyMap[KEY int | string, VALUE float32] map[KEY]VALUEvar m1 MyMap[string, float32] = map[string]float32{"a": 1.1,"b": 1.2,}fmt.Println(m1)
}
  • 其他
	//泛型结构体type MyStruct[T int | string] struct {id   TName stirng}//泛型接口type IPrintData[T int | float32 | string] interface {}//泛型通道type MyChan[T string | int] chan T

泛型函数与方法

package mainimport "fmt"func main() {//给泛型添加方法var s MySlice[int] = []int{1, 2, 3, 4}fmt.Println(s.Sum())var s1 MySlice[float64] = []float64{1.1, 2.1, 3.1, 4.1}fmt.Println(s1.Sum())//泛型函数fmt.Println(Add[int](1, 2))fmt.Println(Add[string]("1", "2"))//如果类型能被自动推断,函数调用时的T可以省略fmt.Println(Add(1, 2))fmt.Println(Add("1", "2"))
}type MySlice[T int | string | float64] []T
func (s MySlice[T]) Sum() T {var sum Tfor _, v := range s {sum += v}return sum
}func Add[T int | float32 | string](a T, b T) T {return a + b
}

实际开发中,泛型使用较多的场景就是泛型的函数与方法。

自定义泛型约束

package mainimport "fmt"func main() {fmt.Println(GetMaxNum(1, 2))fmt.Println(GetMaxNum(1.5, 2.6))
}type MyInt interface {int | int8 | int16 | int32 | float64
}func GetMaxNum[T MyInt](a, b T) T {if a > b {return a}return b
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/630181.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Ubuntu系统使用快速入门实践(八)——出现的各种问题

Ubuntu系统使用快速入门实践系列文章 下面是Ubuntu系统使用系列文章的总链接,本人发表这个系列的文章链接均收录于此 Ubuntu系统使用快速入门实践系列文章总链接 下面是专栏地址: Ubuntu系统使用快速入门实践系列文章专栏 文章目录 Ubuntu系统使用快速…

Eclipse搭建python环境

一、下载eclipse eclipse官网下载参考链接 二、 下载PyDev ​PyDev 三、安装和配置pyDev 下载完PyDev,解压之后是下面两个文件夹,我下载的版本是PyDev 7.7 ,然后拷到eclipse对应的目录下就可以 四、然后新建一个python程序 1.新建一个项目 ​​…

【C语言】数据结构——排序三(归并与计数排序)

💗个人主页💗 ⭐个人专栏——数据结构学习⭐ 💫点击关注🤩一起学习C语言💯💫 目录 导读:1. 归并排序1.1 基本思想1.2 递归实现1.3 非递归实现 2. 计数排序2.1 基本思想2.2 代码实现 导读&#x…

VSCODE上使用IDEA上的快捷键:IntelliJ IDEA Keybindings

🍁 作者:知识浅谈,CSDN签约讲师,CSDN博客专家,华为云云享专家,阿里云专家博主 📌 擅长领域:全栈工程师、爬虫、ACM算法 💒 公众号:知识浅谈 🔥网站…

git项目管理

Git工作流程图 git 基础指令 git init #创建本地仓库,创建成功后,当前目录会多一个.git文件夹 git status #查看修改状态 git add . #添加工作区到暂存区 git commit -m 注释内容 #提交暂存区到本地仓库(commit) git log …

k8s集群环境搭建以及插件安装

前置条件 终端工具MobaXterm很好用。 1、虚拟机三台(ip按自己的网络环境相应配置)(master/node) 节点ipk8s-master192.168.200.150k8s-node1192.168.200.151k8s-node2192.168.200.152 2、关闭防火墙(master/node) systemctl stop firewalld systemc…

导游翻译的职责是什么?如何做好导游翻译?

作为旅游行业的关键人物,导游翻译是连接游客与目的地文化的桥梁。他们不仅要具备出色的语言能力,还要深入了解目的地的历史、文化和风俗习惯,为游客提供专业、贴心的导游翻译服务。那么,导游翻译的主要职责是什么?如何…

idea中设置控制台显示service窗口项

一 操作配置 1.1 具体操作 1.操作 2.操作 3.选择应用类型: appplication,springbootapplication等

AI绘画认识

什么是AI绘画 AI绘画是指利用人工智能技术进行绘画创作的过程,它使用机器学习算法和深度神经网络等技术,通过对现有艺术品、图像等大量数据进行分析和学习,生成新的艺术品或图像。 AI绘画的应用场景非常广泛,包括数字艺术、游戏…

使用 GitHub 远程仓库

使用 GitHub 远程仓库 GitHub 是最大的 Git 版本库托管商,是成千上万的开发者和项目能够合作进行的中心。 大部分 Git 版本库都托管在 GitHub,很多开源项目使用 GitHub 实现 Git 托管、问题追踪、代码审查以及其它事情。本篇文章主要带大家上手 GitHub …

模型Model:文件系统模型QFileSystemModel

一、 1、常用函数 QFileSystemModel自带目录变化监听 1)、 QModelIndex setRootPath(const QString &path); 设置检索根目录 2)、 bool isDir(const QModelIndex &index) const; 选中索引是否为目录节点 3)、 QString filePath(const QModelIndex &index) const;…

Python:list列表与tuple元组的区别

在Python中,List(列表) 和Tuple(元组) 都是用于存储一组有序元素的数据结构,但它们有一些关键的区别,包括可变性、性能、语法等方面。 1. List(列表) 用法:…

Git 提交前缀规范

Git 提交前缀规范 feat : 新功能。添加一个新的用户界面元素、一个新的功能或一个新的 API fix : 修复 bug。修复一个导致应用程序崩溃的错误、一个导致数据丢失的错误或一个导致用户体验不佳的错误 docs : 文档更新。更新你的应用程序的用户指南、更新你的 API 文档或更新你…

【分布式技术】分布式存储ceph之RBD块存储部署

目录 创建 Ceph 块存储系统 RBD 接口 服务端操作 1、创建一个名为 rbd-demo 的专门用于 RBD 的存储池 2、将存储池转换为 RBD 模式 3、初始化存储池 4、创建镜像 5、在管理节点创建并授权一个用户可访问指定的 RBD 存储池 6、修改RBD镜像特性,CentOS7默认情…

算法 - 二分法 / 双指针 / 三指针 / 滑动窗口

文章目录 🍺 二分法🍻 旋转数组🥂 33. 搜索旋转排序数组 [旋转数组] [目标值] (二分法) 🍻 元素边界🥂 34. 在排序数组中查找元素的第一个和最后一个位置 [有序数组] > [元素边界] > (二分法)🥂 81. …

IOS元素定位对应关系

resource-id也称为id,resource-id是唯一的 # 元素定位 agree_continue_id "com.baidu.searchbox:id/positive_button" WebDriverWait(driver, 10, 1).until(EC.visibility_of_element_located((MobileBy.ID, agree_continue_id))) driver.find_element…

Databend 开源周报第 128 期

Databend 是一款现代云数仓。专为弹性和高效设计,为您的大规模分析需求保驾护航。自由且开源。即刻体验云服务:https://app.databend.cn 。 Whats On In Databend 探索 Databend 本周新进展,遇到更贴近你心意的 Databend 。 使用 Databend …

[Linux 进程(四)] 再谈环境变量,程序地址空间初识

文章目录 1、前言2、环境变量2.1 main函数第三个参数 -- 环境参数表2.2 本地环境变量和env中的环境变量2.3 配置文件与环境变量的全局性2.4 内建命令与常规命令2.5 环境变量相关的命令 3、程序地址空间 1、前言 上一篇我们讲了环境变量,如果有不明白的先读一下上一…

C++ 编程需要什么样的开发环境?

C 编程需要什么样的开发环境? 在开始前我有一些资料,是我根据网友给的问题精心整理了一份「C的资料从专业入门到高级教程」, 点个关注在评论区回复“888”之后私信回复“888”,全部无偿共享给大家!!&#…

C++ 拾遗 2

1.变量的作用域 1)全局变量 在整个程序生命周期内都是有效的,在定义位置之后的任意函数中都能访问。 全局变量在主程序退出时由系统收回内存空间。 2)局部变量 在函数或语句块内部的语句使用,在函数或语句块外部是不可用的。 …