【Go专家编程——泛型】

泛型

泛型是程序设计语言的一种风格或范式,它允许程序员在编写代码时使用一些在以后才指定的类型,在实例化时作为参数指明这些类型。Go在1.18引入了泛型

1. 泛型的使用

func SumInts(m map[string]int64) int64 {
	var s int64
	for _, v := range m {
		s += v
	}
	return s
}

func SumFloats(m map[string]float64) float64 {
	var s float64
	for _, v := range m {
		s += v
	}
	return s
}
//使用[]来声明泛型的类型
func SumIntsOrFloats[K comparable, V int64 | float64](m map[K]V) V {
	var s V
	for _, v := range m {
		s += v
	}
	return s
}
//显示调用泛型函数,指明K、V的具体类型
SumIntsOrFloats[string,int64](ints)
//隐式调用泛型函数
SumIntsOrFloats(ints)

编译器能够推导出参数类型的前提是该函数存在入参,编译器通过传入的变量和函数的参数声明可以推导出参数类型,但对于没有函数参数的泛型函数来说,编译器无法进行推导,也就无法实例化泛型函数,所以此时必须显式调用并制定类型参数。

2. 泛型总览

2.1 函数的泛化

Go语言函数通过使用方括号[]表示类型的泛型参数
func SumIntsOrFloats[K comparable, V int64 | float64](m map[K]V) V

2.2 类型的泛化

泛型同样扩展了类型的表示方式,允许在创建自定义类型时也能够接受一个使用方括号([])表示的类型参数,

函数类型与put类型一样,同样允许为其定义方法,但其receiver类型必须带上类型参数

// Vector是可容纳任意类型的容器
type Vector[T any] []T
//推荐的写法
func(v *Vector[T]) Push(x T){
	*v = append(*v, x)
}

//存在,但不推荐
func(v *Vector[Y]) Push(x Y){
	*v = append(*v, x)
}
//存在,但不推荐
func(v *Vector[_]) Push(x _){
	*v = append(*v, x)
}

这里的any等同于interface{}。
在实例化一个泛型类型时,必须指定类型参数(因为编译器无法自动推导)

var intVec Vector[int]//实例化为整型容器
var stringVec Vector[string]//实例化为字符串容器

3.类型约束

3.1 类型集合

func SumIntsOrFloats[K comparable, V int64 | float64](m map[K]V) V我们继续使用前面的函数来说:
在函数的类型参数中:

  • K的类型先定为comparable
  • V的类型限定为int64|float64
  • comparable为interface类型
  • int64|float为组合类型
  • 两者都代表一个类型集合,用于约束泛化的范围

3.2 interface类型集合

interface可以用来表示任何类型集合。
1)内置interface类型集合
comparable和any两个interface都是跟随泛型一起被引入的内置interface类型

type comparable interface{ comparable }表示可比较类型的集合,仅能用于类型参数

type any = interface{}any不仅在类型参数中表示任意类型的集合,还可以在非泛型场景中作为interface{}的别名使用

2)自定义interface类型集合
除了内置的comparable和any两种类型可作为类型约束使用,用户还可以使用interface来定义类型集合。

  • 任意类型元素(如int)
  • 近似类型元素(使用~ 表示,如~64)
  • 联合类型元素(使用|表示,如~ int |~int64)
  • 如果interface类中使用了这三种元素的任意一种,那么这个interface只能用于泛型的类型参数

(1)任意类型元素

type Integer interface{
	int
}
func SumInteger[T Integer](a T,b T) T {
	return a+b
}

(2)近似类型元素
在使用interface声明类型集合时,可以使用~ <type>来指定一组类型,只要其底层类型为同一类型即包含在这个集合中。~ 之后必须是某个底层类型

type AnyString interface{
	~string
}

func SayHi[T AnyString](name T){
	fmt.Printf("Hi %s",name)
}

type MyString string
var s MyString = "John"
SayHi(s)//MyString的底层类型为string,可以实例化

(3)联合类型元素
如果希望把所有底层为有符号整型的类型组合在一起,则可以结合“~”来使用:
例如:

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

3)interface类型集合运算
事实上interface支持按行指定多个子集合,这些子集合取交集形成最终的集合

type MyString interface {
	~string//底层为string的集合
	string//string单一类型
}

取交集后最终的类型集合只包含string一个类型。

4.泛型举例

4.1 MapKeys

任务:将map中的key全部取出形成列表

func MapKeys[K comparable, V any](m map[K]V)[]K{
	r := make([]K,len(m))
	for k := range m {
		r = append(r,k)
	}
	return r
}

4.2 Set

这里利用map实现了一个Set

//set,底层使用map实现
type Set[T comparable] map[T]struct{}
//构造某个comparable类型的set
func MakeSet[T comparable]() Set[T]{
	return make(Set[T])
}
//Add,添加元素V
func (s Set[T]) Add(v T){
	s[v] = struct{}
}
//Delete,删除元素v
func (s Set[T]) Delete(v T){
	delete(s,v)
}
//Contains,查询元素v是否存在
func (s Set[T]) Contains(v T)bool{
	_,ok := s[v]
	return ok
}
//Len,返回元素的个数
func (s Set[T]) Len() int{
	return len(s)
}
//Iterator:遍历Set并逐个调用函数f
func (s Set[T]) Iterate(f func(T)){
	for v := range s {
		f(v)
	}
}

相关推荐

  1. Go专家编程——

    2024-06-06 18:14:01       6 阅读
  2. GO - 编程

    2024-06-06 18:14:01       13 阅读
  3. GO——

    2024-06-06 18:14:01       4 阅读
  4. C++ 编程 模板

    2024-06-06 18:14:01       19 阅读
  5. 如何在Go中使用

    2024-06-06 18:14:01       40 阅读
  6. 一文了解Go

    2024-06-06 18:14:01       34 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-06-06 18:14:01       18 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-06-06 18:14:01       19 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-06-06 18:14:01       19 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-06-06 18:14:01       20 阅读

热门阅读

  1. 【最新鸿蒙应用开发】——数据存储?持久化?

    2024-06-06 18:14:01       10 阅读
  2. Hive on Spark、Spark on Hive的异同

    2024-06-06 18:14:01       7 阅读
  3. pyqt5 tableView实现excel拖曳填充

    2024-06-06 18:14:01       10 阅读
  4. GPT-4o版本间的对比分析和使用心得

    2024-06-06 18:14:01       9 阅读
  5. php设计模式之策略模式详解

    2024-06-06 18:14:01       13 阅读
  6. XML语法规则介绍及总结

    2024-06-06 18:14:01       10 阅读
  7. EasyExcel之动态表头导出不生效

    2024-06-06 18:14:01       8 阅读
  8. 什么叫防御式编程

    2024-06-06 18:14:01       10 阅读
  9. C++:day2

    C++:day2

    2024-06-06 18:14:01      8 阅读