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

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
}

相关文章:

  • Linux网络编程---IP 地址格式转换函数
  • L3上云01 | 分布式、微服务概念
  • 手机常用的root方案
  • 嵌入式-Stm32-江科大基于标准库的GPIO的八种模式
  • vue2 el-table行悬停时弹出提示信息el-popover
  • XXL-Job的搭建接入Springboot项目(详细)
  • RTSP/Onvif安防视频云平台EasyNVR迁移盘符后启动异常的问题排查与解决
  • HashMap学习和线程安全的HashMap
  • 蓝桥杯每日一题----货物摆放
  • web架构师编辑器内容-编辑器组件图层面板功能开发-锁定隐藏、键盘事件功能的开发
  • 中级Python面试问题
  • 概率论与数理统计————3.随机变量及其分布
  • STM32F103标准外设库——中断应用/事件控制器(六)
  • 线性代数的学习和整理23:用EXCEL计算 向量/向量组的点乘 (内积) (建设ing)
  • 数据集成时表模型同步方法解析
  • 实现windows 窗体的自己画,网上摘抄的,学习了
  • CentOS6 编译安装 redis-3.2.3
  • ES6之路之模块详解
  • Eureka 2.0 开源流产,真的对你影响很大吗?
  • JavaScript 基础知识 - 入门篇(一)
  • SpiderData 2019年2月16日 DApp数据排行榜
  • SSH 免密登录
  • STAR法则
  • tab.js分享及浏览器兼容性问题汇总
  • vue:响应原理
  • 阿里研究院入选中国企业智库系统影响力榜
  • 阿里云ubuntu14.04 Nginx反向代理Nodejs
  • 给初学者:JavaScript 中数组操作注意点
  • 关于 Cirru Editor 存储格式
  • 开源中国专访:Chameleon原理首发,其它跨多端统一框架都是假的?
  • 跨域
  • 来,膜拜下android roadmap,强大的执行力
  • 深度学习中的信息论知识详解
  • 实战:基于Spring Boot快速开发RESTful风格API接口
  • 物联网链路协议
  • 想晋级高级工程师只知道表面是不够的!Git内部原理介绍
  • 想使用 MongoDB ,你应该了解这8个方面!
  • 国内开源镜像站点
  • ​​​​​​​​​​​​​​汽车网络信息安全分析方法论
  • # 达梦数据库知识点
  • #我与Java虚拟机的故事#连载13:有这本书就够了
  • $().each和$.each的区别
  • $.ajax()方法详解
  • (arch)linux 转换文件编码格式
  • (delphi11最新学习资料) Object Pascal 学习笔记---第2章第五节(日期和时间)
  • (Redis使用系列) SpringBoot中Redis的RedisConfig 二
  • (附源码)流浪动物保护平台的设计与实现 毕业设计 161154
  • (三) prometheus + grafana + alertmanager 配置Redis监控
  • (一)Thymeleaf用法——Thymeleaf简介
  • (转)fock函数详解
  • (转)IIS6 ASP 0251超过响应缓冲区限制错误的解决方法
  • ******之网络***——物理***
  • .NET Standard / dotnet-core / net472 —— .NET 究竟应该如何大小写?
  • .Net开发笔记(二十)创建一个需要授权的第三方组件
  • .NET中GET与SET的用法