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)
}
相关文章
|
7月前
|
Go
【Golang】使用泛型对数组进行去重
【2月更文挑战第11天】使用泛型对数组进行去重
75 0
|
存储 安全 Java
|
Go Python 容器
因势而变,因时而动,Go lang1.18入门精炼教程,由白丁入鸿儒,Go lang泛型(generic)的使用EP15
事实上,泛型才是Go lang1.18最具特色的所在,但为什么我们一定要拖到后面才去探讨泛型?类比的话,我们可以想象一下给小学一年级的学生讲王勃的千古名篇《滕王阁序》,小学生有多大的概率可以理解作者的青云之志以及壮志难酬的愤懑心情?恐怕很难罢,是的,如果对Go lang的强类型语法没有一段时间的体验期,就很难理解泛型这种“反”静态语言概念。
因势而变,因时而动,Go lang1.18入门精炼教程,由白丁入鸿儒,Go lang泛型(generic)的使用EP15
|
Java Linux Go
知识分享之Golang——Golang1.18泛型的简单案例
知识分享之Golang篇是我在日常使用Golang时学习到的各种各样的知识的记录,将其整理出来以文章的形式分享给大家,来进行共同学习。欢迎大家进行持续关注。 知识分享系列目前包含Java、Golang、Linux、Docker等等。
102 0
知识分享之Golang——Golang1.18泛型的简单案例
|
编译器 Go
Golang泛型语法
在定义函数(结构等)时候,可能会有多种类型传入。只有在真正使用才知道是什么类型,此时就可以用一个更加宽泛的类型(必须存在一定约束,只能在那些类型的范围内使用)暂时占位。这个类型就叫泛型
841 0
|
安全 Java Go
Golang出现泛型后,Gin怎么封装网络请求处理
Go 1.18后出现泛型,小白怎么使用Gin框架怎么根据泛型封装客户端请求,
564 0
|
3月前
|
Go
Golang语言之管道channel快速入门篇
这篇文章是关于Go语言中管道(channel)的快速入门教程,涵盖了管道的基本使用、有缓冲和无缓冲管道的区别、管道的关闭、遍历、协程和管道的协同工作、单向通道的使用以及select多路复用的详细案例和解释。
140 4
Golang语言之管道channel快速入门篇
|
3月前
|
Go
Golang语言文件操作快速入门篇
这篇文章是关于Go语言文件操作快速入门的教程,涵盖了文件的读取、写入、复制操作以及使用标准库中的ioutil、bufio、os等包进行文件操作的详细案例。
71 4
Golang语言文件操作快速入门篇
|
3月前
|
Go
Golang语言之gRPC程序设计示例
这篇文章是关于Golang语言使用gRPC进行程序设计的详细教程,涵盖了RPC协议的介绍、gRPC环境的搭建、Protocol Buffers的使用、gRPC服务的编写和通信示例。
112 3
Golang语言之gRPC程序设计示例
|
3月前
|
安全 Go
Golang语言goroutine协程并发安全及锁机制
这篇文章是关于Go语言中多协程操作同一数据问题、互斥锁Mutex和读写互斥锁RWMutex的详细介绍及使用案例,涵盖了如何使用这些同步原语来解决并发访问共享资源时的数据安全问题。
100 4