Golang泛型详细介绍

简介: Golang泛型详细介绍

前言

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

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


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

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

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

func sumInt(a, b int) int {
   
    return a + b
}

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

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
  }
}

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

func sum_Int_Float[T int|float64](a,b T) T {
   
  return a + b
}

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


二、泛型语法详解

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

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已经被去除掉了,详细原因

// 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的类型

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外,定义泛型结构体变量:
type Struct1 [T string|int|float64] struct {
   
  Title string
  Content  T
}

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

stu := struct{
   
  Name string
  Age int
  Weight float64
}{
   
  "smallyang",
  18,
  50.5,
}
fmt.Println("Student =", stu) // Student = {smallyang 18 50.5}

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

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
*/

  • 泛型数组变量:
type slice[T any] []T

等等...


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

1、操作slice

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、操作指针

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

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)
}
相关文章
|
2月前
|
Go
【Golang】使用泛型对数组进行去重
【2月更文挑战第11天】使用泛型对数组进行去重
31 0
|
6月前
|
存储 安全 Java
|
Go Python 容器
因势而变,因时而动,Go lang1.18入门精炼教程,由白丁入鸿儒,Go lang泛型(generic)的使用EP15
事实上,泛型才是Go lang1.18最具特色的所在,但为什么我们一定要拖到后面才去探讨泛型?类比的话,我们可以想象一下给小学一年级的学生讲王勃的千古名篇《滕王阁序》,小学生有多大的概率可以理解作者的青云之志以及壮志难酬的愤懑心情?恐怕很难罢,是的,如果对Go lang的强类型语法没有一段时间的体验期,就很难理解泛型这种“反”静态语言概念。
因势而变,因时而动,Go lang1.18入门精炼教程,由白丁入鸿儒,Go lang泛型(generic)的使用EP15
|
编译器 Go
Golang泛型语法
在定义函数(结构等)时候,可能会有多种类型传入。只有在真正使用才知道是什么类型,此时就可以用一个更加宽泛的类型(必须存在一定约束,只能在那些类型的范围内使用)暂时占位。这个类型就叫泛型
629 0
|
安全 Java Go
Golang出现泛型后,Gin怎么封装网络请求处理
Go 1.18后出现泛型,小白怎么使用Gin框架怎么根据泛型封装客户端请求,
467 0
|
Java 编译器 Linux
知识分享之Golang——Golang1.18正式发布泛型到来
知识分享之Golang篇是我在日常使用Golang时学习到的各种各样的知识的记录,将其整理出来以文章的形式分享给大家,来进行共同学习。欢迎大家进行持续关注。 知识分享系列目前包含Java、Golang、Linux、Docker等等。
130 0
知识分享之Golang——Golang1.18正式发布泛型到来
|
Java Linux Go
知识分享之Golang——Golang1.18泛型的简单案例
知识分享之Golang篇是我在日常使用Golang时学习到的各种各样的知识的记录,将其整理出来以文章的形式分享给大家,来进行共同学习。欢迎大家进行持续关注。 知识分享系列目前包含Java、Golang、Linux、Docker等等。
79 0
知识分享之Golang——Golang1.18泛型的简单案例
|
8天前
|
监控 算法 Go
Golang深入浅出之-Go语言中的服务熔断、降级与限流策略
【5月更文挑战第4天】本文探讨了分布式系统中保障稳定性的重要策略:服务熔断、降级和限流。服务熔断通过快速失败和暂停故障服务调用来保护系统;服务降级在压力大时提供有限功能以保持整体可用性;限流控制访问频率,防止过载。文中列举了常见问题、解决方案,并提供了Go语言实现示例。合理应用这些策略能增强系统韧性和可用性。
36 0
|
6天前
|
分布式计算 Java Go
Golang深入浅出之-Go语言中的分布式计算框架Apache Beam
【5月更文挑战第6天】Apache Beam是一个统一的编程模型,适用于批处理和流处理,主要支持Java和Python,但也提供实验性的Go SDK。Go SDK的基本概念包括`PTransform`、`PCollection`和`Pipeline`。在使用中,需注意类型转换、窗口和触发器配置、资源管理和错误处理。尽管Go SDK文档有限,生态系统尚不成熟,且性能可能不高,但它仍为分布式计算提供了可移植的解决方案。通过理解和掌握Beam模型,开发者能编写高效的数据处理程序。
134 1
|
7天前
|
缓存 测试技术 持续交付
Golang深入浅出之-Go语言中的持续集成与持续部署(CI/CD)
【5月更文挑战第5天】本文介绍了Go语言项目中的CI/CD实践,包括持续集成与持续部署的基础知识,常见问题及解决策略。测试覆盖不足、版本不一致和构建时间过长是主要问题,可通过全面测试、统一依赖管理和利用缓存优化。文中还提供了使用GitHub Actions进行自动化测试和部署的示例,强调了持续优化CI/CD流程以适应项目需求的重要性。
45 1