Golang泛型的使用方法详解

 更新时间:2022年12月14日 09:07:27   作者:梦想画家  
这篇文章主要介绍了Golang中泛型的使用,Go和Python语言不同,处理不同数据类型非常严格。如Python可以定义函数带两个数值类型并返回较大的数值,但可以不严格指定参数类型为float或integer

Go 和Python语言不同,处理不同数据类型非常严格。如Python可以定义函数带两个数值类型并返回较大的数值,但可以不严格指定参数类型为float或integer。同样功能go1.18之前版本需要定义两个函数分别处理对应类型,通过泛型可以实现上面描述功能,无需为每种类型重复定义函数。

本文通过示例学习Go泛型,包括三个部分:非泛型函数,泛型函数,泛型类型约束。

泛型的作用

我们知道Go一些函数(如fmt.Println)使用空interface支持多种数据类型,但需要开发者写大量代码实现很多函数或方法支持多种自定义类型不是最佳选项,于是泛型登场,提供新的解决方案,无需使用接口和反射支持多种数据类型。

下面通过示例来说明:

package main
import (
    "fmt"
)
func Print[T any](s []T) {
    for _, v := range s {
        fmt.Print(v, " ")
    }
    fmt.Println()
}
func main() {
    Ints := []int{1, 2, 3}
    Strings := []string{"One", "Two", "Three"}
    Print(Ints)
    Print(Strings)
}

上面代码种Print()函数使用泛型,通过在函数名称和参数之间增加[T any]指定泛型变量, 既然T 为any类型,函数可传入任何数据类型slice。当然Print函数不能处理slice之外的输入,这是因为函数实现决定的。通过泛型函数可以避免针对每种数据类型编写函数,这种通用的思想就是泛型。

非泛型函数

我们实现两个函数,返回数值类型数组元素的和。我们至少创建两个函数,一个针对float64类型,另一个为int64,因此工作量翻倍。

package main
import "fmt"
func main() {
   f := []float64{1.0, 2.0, 3.0, 4.0, 5.0}
   i := []int64{1, 2, 3, 4, 5}
   s1 := SumOfFloat(f)
   s2 := SumOfIntegers(i)
   fmt.Println("Sum for float64 :", s1)
   fmt.Println("Sum for int64 :", s2)
}
func SumOfFloat(nums []float64) float64 {
   var sum float64
   for _, num := range nums {
       sum += num
   }
   return sum
}
func SumOfIntegers(nums []int64) int64 {
   var sum int64
   for _, num := range nums {
       sum += num
   }
   return sum
}

运行输出结果:

$ go run main.go
Sum for float64 : 15
Sum for int64 : 15

上面代码针对两种类型定义了两个函数,返回各自参数对应类型数组元素之和。下面通过泛型合并两个函数为一个,节约时间和精力。

泛型函数

本节实现单个函数,参数仍然是数组,但类型可以为float64或int64,并返回数组元素之和,从而可以代替上面两个函数。

为了能够定义函数接收float64和int64两种类型,新的泛型函数需要声明接收的类型,即调用代码需要判断类型是否为float64或int64。为此,新的函数签名需要有点变化,除了普通的参数外,还需要声明类型参数,从而转换函数为泛型函数支持不同类型。

每个形参都有一个类型约束,它指定调用代码可用于形参允许的实参类型。在编译时这些参数表示的类型就是调用代码支持的类型。当然泛型函数的实现逻辑需要支持形参声明的所有类型。举例,泛型函数支持字符串和数值参数,函数实现逻辑需要对参数进行索引,显然数值无法索引将引起编译错误。

泛型函数语法:

func genericFunction[T any](s []T) []T{

}

解释如下:

上面语法种在名称和参数之间的[]用于指定形式参数类型,可以是一组类型或一个约束接口。T 参数类型,用于定义形式参数和返回值类型。

函数内部也可以访问参数,any 是一个interfaceT必须实现该接口。Go1.18版本引入any,底层引用空接口,即interface{}。 下面举例说明:

package main
import "fmt"
func main() {
   f := []float64{1.0, 2.0, 3.0, 4.0, 5.0}
   i := []int64{1, 2, 3, 4, 5}
   s1 := genericSum(f)
   s2 := genericSum(i)
   fmt.Println("Sum for float64 :", s1)
   fmt.Println("Sum for int64 :", s2)
}
func genericSum[N int64 | float64](nums []N) N {
   var sum N
   for _, num := range nums {
       sum += num
   }
   return sum
}

输出结果:

$ go run main.go
Sum for float64 : 15
Sum for int64 : 15

上面示例中演示定义泛型函数genericSum。参数类型在[]中声明的泛型类型。N声明在形参和返回值中使用,N是新的类型,被限定了两种类型float64 和 int64的联合类型。

在函数体类,首先声明N类型变量,然后遍历数组计算综合并返回。

假设泛型函数支持很多种类型,比如:int, int8 , int26, int32, int64, float32, float64。这样函数签名变得非常冗长难看,我们可以定义一个类型包括上述类型,本质上就是把联合类型迁移至函数声明外面。

package main
import "fmt"
type Number interface {
   int64 | float64
}
func main() {
   f := []float64{1.0, 2.0, 3.0, 4.0, 5.0}
   i := []int64{1, 2, 3, 4, 5}
   s1 := genericSum(f)
   s2 := genericSum(i)
   fmt.Println("Sum for float64 :", s1)
   fmt.Println("Sum for int64 :", s2)
}
func genericSum[N Number](nums []N) N {
   var sum N
   for _, num := range nums {
       sum += num
   }
   return sum
}

总结

本文是关于Go泛型的,因为泛型是Golang的新成员。通过对比带泛型和不带泛型的函数,泛型可以很明显地节省时间和精力。泛型不是接口的替代品,两者被设计为一起工作,避免重复代码,让Go类型更安全、代码更整洁。

到此这篇关于Golang泛型的使用方法详解的文章就介绍到这了,更多相关Golang泛型内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Golang极简入门教程(二):方法和接口

    Golang极简入门教程(二):方法和接口

    这篇文章主要介绍了Golang极简入门教程(二):方法和接口,本文同时讲解了错误、匿名域等内容,需要的朋友可以参考下
    2014-10-10
  • GO如何模拟流操作实现示例探究

    GO如何模拟流操作实现示例探究

    这篇文章主要为大家介绍了GO如何模拟流操作实现示例探究,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2024-01-01
  • Golang channel关闭的实现示例

    Golang channel关闭的实现示例

    channel关闭不当或不关闭会引发很多问题,本文主要介绍了Golang channel关闭的实现示例,具有一定的参考价值,感兴趣的可以了解一下
    2024-01-01
  • Go语言操作mysql数据库简单例子

    Go语言操作mysql数据库简单例子

    这篇文章主要介绍了Go语言操作mysql数据库简单例子,本文包含插入数据和查询代码实例,需要的朋友可以参考下
    2014-10-10
  • Golang开发中常用的代码片段汇总

    Golang开发中常用的代码片段汇总

    这篇文章主要给大家汇总了在Golang开发中常用的代码片段,这些代码片段都是在日常工作中编写golang应用时使用到,需要的朋友可以参考借鉴,下面跟着小编一起来学习学习吧。
    2017-07-07
  • 详解Go语言如何判断两个对象是否相等

    详解Go语言如何判断两个对象是否相等

    在编程中,判断两个对象是否相等是一项常见的任务,同时判断对象是否相等在很多情况下都非常重要,所以在接下来的内容中,我们将详细介绍在 Go 语言中如何判断对象是否相等的方法和技巧,需要的可以参考一下
    2023-06-06
  • golang代码中调用Linux命令

    golang代码中调用Linux命令

    本文主要介绍了golang代码中调用Linux命令,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-02-02
  • GO语言判断一个网段是否属于另一个网段的子网

    GO语言判断一个网段是否属于另一个网段的子网

    这篇文章主要介绍了GO语言判断一个网段是否属于另一个网段的子网的相关资料,内容介绍详细,具有一定的参考价值,需要的朋友可任意参考一下
    2022-03-03
  • Go语言中如何实现并发

    Go语言中如何实现并发

    Go的并发机制通过协程和通道的简单性和高效性,使得编写并发代码变得相对容易,这种并发模型被广泛用于构建高性能的网络服务、并行处理任务和其他需要有效利用多核处理器的应用程序,这篇文章主要介绍了在Go中如何实现并发,需要的朋友可以参考下
    2023-09-09
  • Golang HTTP 服务平滑重启及升级的思路

    Golang HTTP 服务平滑重启及升级的思路

    Golang HTTP服务在上线时,需要重新编译可执行文件,关闭正在运行的进程,然后再启动新的运行进程。这篇文章主要介绍了Golang HTTP 服务平滑重启及升级,需要的朋友可以参考下
    2020-04-04

最新评论