首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >GO语言之泛型应用

GO语言之泛型应用

作者头像
阿珍
发布2025-07-08 18:19:21
发布2025-07-08 18:19:21
12500
代码可运行
举报
运行总次数:0
代码可运行

在之前都未接触过泛型,在之前偶然听别人提及过泛型这东西,所以就学习总结一下go的泛型使用

一、为什么泛型会在新版的go中加入?


一个简单的例子来比较用泛型和不用泛型的区别

  • 需求:封装一个函数来实现对多种类型(int、float...)进行加法运算

由于函数的入参的类型只能定义一个

代码语言:javascript
代码运行次数:0
运行
复制
go 体验AI代码助手 代码解读复制代码func sumInt(a, b int) int {
	return a + b
}

所以我们只能使用interface作为入参在利用反射进行类型判断来实现

代码语言:javascript
代码运行次数:0
运行
复制
go 体验AI代码助手 代码解读复制代码func sum_Int_Float(a, b interface{}) interface{} {
  switch a.(type) {
  case int:
    a1 := a.(int)
    b1 := b.(int)
    return a1 + b1
  case float64:
    a1 := a.(float64)
    b1 := b.(float64)
    return a1 + b1
  default:
    return nil
  }
}

但是使用泛型的话那么将是这个样子

代码语言:javascript
代码运行次数:0
运行
复制
go 体验AI代码助手 代码解读复制代码func sum_Int_Float[T int|float64](a,b T) T {
  return a + b
}

这样看下来使用泛型会简洁很多


二、泛型语法详解

一个简单的泛型大概是这样的

代码语言:javascript
代码运行次数:0
运行
复制
go 体验AI代码助手 代码解读复制代码func MyPrintln[T any](a T) {
	fmt.Println(a)
}

func main() {
	MyPrintln("nb")
    //运行结果:
	//nb
}

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

  • MyType可以是函数名, 结构体名, 类型名…
  • T1, T2…是泛型名, 可以随便取
  • constraint的意思是约束,是泛型中最重要的概念, T满足其中之一即可(如T1可以是constraint1和constraint2中的任何一个)

三、constraint约束

在之前的例子中func MyPrintln[T any](a T)any就是一个约束 不过看any的底层代码type any = interface{}可知any就跟interface一样


而go中的约束大概是有这些

any(interface{} Interger Float comparable (可比较) ...


自定义constraint

然后我们可以看看constraint包里的约束是怎么构造的,然后我们就可以自定义constraint(但是正式版的constraints已经被去除掉了,详细原因

代码语言:javascript
代码运行次数:0
运行
复制
go 体验AI代码助手 代码解读复制代码// 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
}
//......

由此我们可知道怎样去自定义约束了

例如我们想定义一个map,限制它的k,v的类型

代码语言:javascript
代码运行次数:0
运行
复制
go 体验AI代码助手 代码解读复制代码type myCompare interface {
	~int | ~float64 | [5]interface{} | struct{}
}

type myint interface {
	~int8|~int64
}
type myfloat interface {
	~float64|~float32
}

type MyMap[K myCompare, V myfloat | myint] map[K]V

这样子我们就定义了一个自己的map


  • 除map外,定义泛型结构体变量:
代码语言:javascript
代码运行次数:0
运行
复制
go 体验AI代码助手 代码解读复制代码type Struct1 [T string|int|float64] struct {
  Title string
  Content  T
}

而对于结构体,结构体可以进行匿名操作 即把结构体的申明定义和初始化一起完成,举个例子

代码语言:javascript
代码运行次数:0
运行
复制
go 体验AI代码助手 代码解读复制代码stu := struct{
  Name string
  Age int
  Weight float64
}{
  "smallyang",
  18,
  50.5,
}
fmt.Println("Student =", stu) // Student = {smallyang 18 50.5}

但是如果对泛型定义的结构体是不支持匿名的

代码语言:javascript
代码运行次数:0
运行
复制
go 体验AI代码助手 代码解读复制代码stu2 := struct[T int|float64] {
  Name   string
  Age    int
  Weight T
}[int]{
  "smallyang",
  18,
  50,
}
fmt.Println("Student =", stu2)

/*
./main.go:70:16: syntax error: unexpected [, expecting {
./main.go:72:10: syntax error: unexpected int at end of statement
./main.go:73:10: syntax error: unexpected T at end of statement
./main.go:74:3: syntax error: unexpected [ after top level declaration
*/

  • 泛型数组变量:
代码语言:javascript
代码运行次数:0
运行
复制
go 体验AI代码助手 代码解读复制代码type slice[T any] []T

等等...


四、泛型中操作各种数据类型的例子示范

1、操作slice

代码语言:javascript
代码运行次数:0
运行
复制
go 体验AI代码助手 代码解读复制代码package main

import (
	"fmt"
)

type slice[T any] []T

type mySlice interface {  自定义constraint
	~int | ~string
}

func printSlice[T mySlice](s []T) {
	for _, v := range s {
		fmt.Printf("%v ", v)
	}
	fmt.Print("\n")
}

func main() {
	vs := slice[int]{1, 2, 3, 4}
	printSlice(vs)

	vs2 := slice[string]{"a", "b"}
	printSlice(vs2)
}

2、操作指针

代码语言:javascript
代码运行次数:0
运行
复制
go 体验AI代码助手 代码解读复制代码package main
 
import (
  "fmt"
)
 
func pointerOf[T any](v T) *T {
  return &v
}
 
func main() {
  sp := pointerOf("foo")
  fmt.Println(*sp)
 
  ip := pointerOf(123)
  fmt.Println(*ip)
  *ip = 234
  fmt.Println(*ip)
}

3、操作map

代码语言:javascript
代码运行次数:0
运行
复制
go 体验AI代码助手 代码解读复制代码package main
 
import (
  "fmt"
)
 
func mapFunc[T any, M any](a []T, f func(T) M) []M {
  n := make([]M, len(a), cap(a))
  for i, e := range a {
    n[i] = f(e)
  }
  return n
}
 
func main() {
  vi := []int{1, 2, 3, 4, 5, 6}
  vs := mapFunc(vi, func(v int) string {
    return "<" + fmt.Sprint(v*v) + ">"
  })
  fmt.Println(vs)
}

本文系转载,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文系转载前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、为什么泛型会在新版的go中加入?
  • 二、泛型语法详解
  • 三、constraint约束
    • 自定义constraint
  • 四、泛型中操作各种数据类型的例子示范
    • 1、操作slice
    • 2、操作指针
    • 3、操作map
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档