经过这几年的千呼万唤,简洁的Go语言终于在1.18版本迎来泛型编程。

泛型是什么

在我看来泛型其实用C++的模板一词来描述就非常的准确。在写代码的时候,我们经常需要写很多重复的逻辑,一般这个时候我们就会使用函数来对其进行封装。但是由于Go是一种强类型语言,所以在定义和书写函数的时候需要在调用前标明类型。当然如果这一重复的逻辑只需要固定的类型,这样就足够了,但是很多时候我们需要不同的类型进行类似的逻辑,譬如我们刚刚看到的GIF。对于普通开发人员来说这种情况可能遇到的比较少,但是在一些库开发人员来说,这种情况变得非常的普遍。

泛型程序设计(generic programming)是程序设计语言的一种风格或范式。泛型允许程序员在强类型程序设计语言中编写代码时使用一些以后才指定的类型,在实例化时作为参数指明这些类型。各种程序设计语言和其编译器、运行环境对泛型的支持均不一样。Ada、Delphi、Eiffel、Java、C#、F#、Swift 和 Visual Basic .NET 称之为泛型(generics);ML、Scala 和 Haskell 称之为参数多态(parametric polymorphism);C++ 和 D称之为模板。具有广泛影响的1994年版的《Design Patterns》一书称之为参数化类型(parameterized type)。

例如:

vector<int> v;
v.push_back(1);

中的int就指定了v中存储元素的类型为int, 也可以替换成其他你想要存储的类型

自定义模板, 只需要:

template<class T>
class Vector{int mLen;T* data;
};

又比如Java中也有泛型的概念:

class Vector<T>{public void push_back(T val){//implement...}
}

Go的泛型

泛型语法详解

MyType[T1 constraint1 | constraint2, T2 constraint3...] ...

泛型的语法非常简单, 就类似于上面这样, 其中:

  • MyType可以是函数名, 结构体名, 类型名…
  • T1, T2…是泛型名, 可以随便取
  • constraint的意思是约束, 也是泛型中最重要的概念, 接下来会详解constraint
  • 使用 | 可以分隔多个constraint, T满足其中之一即可(如T1可以是constraint1和constraint2中的任何一个)

Constraint(约束)是什么

约束的意思是限定范围, constraint的作用就是限定范围, 将T限定在某种范围内

而常用的范围, 我们自然会想到的有:

  • any(interface{}, 任何类型都能接收, 多方便啊!)
  • Interger(所有int, 多方便啊, int64 int32…一网打尽)
  • Float(同上)
  • comparable(所有可以比较的类型, 我们可以给所有可以比较的类型定制一些方法)

这些约束, 不是被官方定义为内置类型, 就是被涵盖在了constraints包内。

下面是builtin.go的部分官方源码:

// any is an alias for interface{} and is equivalent to interface{} in all ways.
type any = interface{}// comparable is an interface that is implemented by all comparable types
// (booleans, numbers, strings, pointers, channels, interfaces,
// arrays of comparable types, structs whose fields are all comparable types).
// The comparable interface may only be used as a type parameter constraint,
// not as the type of a variable.
type comparable comparable

下面是constraints.go的部分官方源码:

// Integer is a constraint that permits any integer type.
// If future releases of Go add new predeclared integer types,
// this constraint will be modified to include them.
type Integer interface {Signed | Unsigned
}// Float is a constraint that permits any floating-point type.
// If future releases of Go add new predeclared floating-point types,
// this constraint will be modified to include them.
type Float interface {~float32 | ~float64
}
//......

自定义constraint(约束)

type Signed interface {~int | ~int8 | ~int16 | ~int32 | ~int64
}

Signed约束就是这样被写出来的, 其中需要我们get的点有如下几个:

  • 使用interface{}就可以自定义约束
  • 使用 | 就可以在该约束中包含不同的类型, 例如int, int8, int64均满足Signed约束

泛型使用案例

基本使用

首先从最常用的max函数来看。 假设我现在需要两个int类型的最大值,原先的Go写法是:

package mainimport "fmt"func main() {fmt.Println(maxInt(32, 64))
}func maxInt(a, b int) int {if a > b {return a}return b
}

这个时候我需要增加一个获取float64的最大值,那么我们就要新增一个函数叫maxFloat64:

func maxFloat64(a, b float64) float64 {if a > b {return a}return b
}

每当我们需要对一种类型进行比较的时候,我们都需要重新编写一个函数,尽管他们的逻辑其实都是一样的,将来甚至还需要int8、int16、int32等等的类型。

当引入泛型之后,我们可以写成:

package mainimport ("fmt"
)func main() {fmt.Println(max(1, 2))fmt.Println(max[int32](1, 2))fmt.Println(max(1.5, 2.3))
}func max[T int | int8 | int16 | int32 | int64 | float32 | float64](a, b T) T {if a > b {return a}return b
}

当然,后面跟了一长串的int|int8、、、这样实在有点费劲,如果我们之后需要增加一个min函数呢,岂不是又要把上面的这些抄一遍吗,所以这里还可以用interface提前定义下:

package mainimport ("fmt"
)func main() {fmt.Println(max(1, 2))fmt.Println(max[int32](1, 2))fmt.Println(max(1.5, 2.3))fmt.Println(min(1, 2))fmt.Println(min[int32](1, 2))fmt.Println(min(1.5, 2.3))}type Number interface {int | int8 | int16 | int32 | int64 | float32 | float64
}func max[T Number](a, b T) T {if a > b {return a}return b
}func min[T Number](a, b T) T {if a < b {return a}return b
}

在结构体中使用泛型

除了函数声明中可以使用泛型,结构体中一样可以使用:

package mainimport ("fmt"
)type Data[T comparable] struct {Message T
}func (d Data[T]) Print() {fmt.Println(d.Message)
}func main() {d := Data[int]{Message: 66,}d.Print()
}

这里有个类型:comparable

可以看看go的源码里面写的:

// comparable is an interface that is implemented by all comparable types
// (booleans, numbers, strings, pointers, channels, arrays of comparable types,
// structs whose fields are all comparable types).
// The comparable interface may only be used as a type parameter constraint,
// not as the type of a variable.
type comparable interface{ comparable }

大概意思就是允许booleans, numbers, strings, pointers, channels, comparable类型组成的arrays以及所有字段都是由comparable类型组成的struct。

这里也有一个any类型:

// any is an alias for interface{} and is equivalent to interface{} in all ways.
type any = interface{}

Go1.8 泛型简单上手使用相关推荐

  1. Go1.18泛型使用详解(附最新gocode)

    原文地址:Go1.18版本泛型详解_耀一世风光的博客-CSDN博客_go 泛型go1.18泛型详解https://blog.csdn.net/qq_52582768/article/details/1 ...

  2. java泛型特点_java泛型简单总结

    Java泛型简单总结 1)基本概念: 泛型(Generic Type或Generics)是 对Java语言的类型系统的一种扩展,以支持创建可以按类型进行参数化的类.可以把类型参数看做是使用参数化类型时 ...

  3. Java基础之泛型简单讲解(通俗易懂)

    Java基础之泛型简单讲解(通俗易懂) 1. 前言 2. 简单例子对比理解 2.1 未使用泛型例子--ArrayList 2.2 使用泛型的例子 2.2.1 ArrayList 举例 2.2.2 Ha ...

  4. linux脚本量产,可玩性很高的量产键盘、套件 HEAVY SHELL KIRA 96简单上手

    1.jpg (45.97 KB, 下载次数: 4) 可玩性很高的量产键盘.套件 HEAVY SHELL KIRA 96简单上手 2021-2-2 14:20 上传HEAVY SHELL Kira 96 ...

  5. 【有趣的Python小程序】Python多个简单上手的库制作WalkLattice 走格子游戏 (思路篇)上

    篇写上一个思路篇,那么今天我们就来完成这一项工作 源代码和配套文件 链接: https://caiyun.139.com/m/i?135ClY1yWrSKX 提取码:e4pq 复制内容打开中国移动云盘 ...

  6. 哈希宝-简单上手教程

    闲来无事做点什么 没有入场的不建议入场,使用已有设备,赚取额外收益即可 随着kuang潮的兴起,越来越多人开始挖kuang,但是"正确的上网姿势".钱包.kuang池.币种等等让人 ...

  7. 红米note7找android,红米note7荣耀v20简单上手体验

    红米note7&荣耀v20简单上手体验 2019-02-03 12:31:00 49点赞 22收藏 41评论 起因是老爸说自己手机不太好用了,让我给买个新的,后来我老婆也表示现在用的小米6屏也 ...

  8. STM32F429I-Discovery学习笔记--(1)简单上手和官方例程的下载与使用

    STM32F429I-Discovery学习笔记–(1)简单上手和官方例程的下载与使用 到手测试 收到开发板后我们要首先检查一下外观有没有磕碰破损,排针是否发生弯折,重要的是看一下JP3和CN4处的跳 ...

  9. python wxpy模块,python wxpy模块 (一)简单上手

    简单上手 登陆微信: 导入模块 from wxpy import * 初始化机器人,扫码登陆 bot = Bot() 找到好友: 搜索名称含有 "游否" 的男性深圳好友 my_fr ...

最新文章

  1. CTFshow php特性 web143
  2. 阿里集团搜索和推荐关于效率稳定性的思考和实践
  3. 云数据库RDS_MySQL购买流程_以及购买步骤的建议
  4. 阿里云开源的Blink,计算能力很疯狂:一眨眼,全部都算好!
  5. 2018蓝桥杯省赛---java---C---1(哪天返回)
  6. C++ 中的 #pragma warning(push) 和 #pragma warning(pop)有什么用
  7. 1.3编程基础之算术表达式与顺序执行(20题)-2022.02.26
  8. JNI_Android项目中调用.so动态库实现详解【转】
  9. 基于vue-cli3+typescript+element-ui搭建起来的后端管理平台框架(骨架)
  10. Failed to restart docker.service: Unit is masked.真正的解决办法
  11. [em] [/em] 表情 代码 如何使用 qq空间代码
  12. html 格式化日期
  13. 织梦后台登录后页面一片空白怎么办?
  14. 如何在Debian系统下搭建SVN
  15. 求求你别再写上千行的类了,试试 IDEA 这些牛逼的重构技巧吧!
  16. 个人承接微信H5制作设计,需要的联系我
  17. python面向对象OOP编程(三)-- 同类 不同实例 之间的关联关系
  18. 15.7数据库(7):MySQL创建校园数据库
  19. 简易计算器软件系统测试计划,Windows自带的计算器测试计划.doc
  20. 基于vue与element-ui写出的关于搜索框搜索关键字,下方关键字高亮的demo

热门文章

  1. 并发访问oracle数据库的数据死锁分析和解决措施,解决Oracle数据库死锁
  2. 取消坐标轴上边和右边边框
  3. 10种图算法直观可视化解释
  4. SQLite数据库表字段修改与删除
  5. 浪潮服务器挂载文件,2.2.挂载云硬盘
  6. 牛客NC15976--小C的周末(并查集+map计数)
  7. 极验验证码破解—超详细教程(三)
  8. Linux CentOS7防火墙端口设置
  9. 安装Pytorch时NVIDIA驱动更新,CUDA版本问题
  10. 图论算法及其matlab实现 程序,图论算法及其matlab程序代码.doc