隐藏页面特效

golang泛型简介

linux下go版本安装(1.18.1版本)

>>> wget https://go.dev/dl/go1.18.1.linux-amd64.tar.gz >>> tar xzvf go1.18.1.linux-amd64.tar.gz -C /usr/local >>> mkdir /data/go_path -p >>> vim ~/.bashrc export GOROOT=/usr/local/go export GOPATH=/data/go_path export GOPROXY=https://goproxy.cn export PATH=$PATH:$GOROOT/bin::$GOPATH/bin >>> source ~/.bashrc

编写泛型函数

让我们看看如何在go中构建自己的泛型函数开始。传统上,你将从一个函数签名开始,该签名将明确说明此函数期望作为参数的类型:

func oldNonGenricFunc(myAge int64){ fmt.Println(myAge) }

在新版本中,如果我们想创建一个可以接收int64float64类型的函数,我们可以像这样修改我们的函数签名:

package main import "fmt" func newGenericFunc[age int64 | float64](myAge age){ fmt.Println(myAge) } func main(){ fmt.Println("Go Generics Tutorial") var testAge int64 = 23 var testAge2 float64 = 24.5 newGenericFunc(testAge) newGenericFunc(testAge2) }

运行结果:

[root@wei demo_generics]# go run main.go go generics 23 24.5

所以, 让我们分解一下我们在这里所做的时区。我们有效的创建了一个名为newGenericFunc函数,在我们的函数名称之后,我们打开方括号[]并指定我们可以合理地期望我们的函数被调用的类型:

[age int64 | float64]

当我们在括号中定义函数的参数时,我们说变量myAge可以是类型age, 随后可以是int64或者float64类型。

注意,如果我们想添加更多类型,我们可以使用|不同类型之间的分隔符列出更多类型。

使用任何类型

在上面的列子中,我们指定了一个可以接受多种类型的泛型函数int64float64,但是,如果我们想要定义一个可以接受任何类型的函数怎么办?

我们可以像下面这样使用新的内置any类型:

package main import "fmt" func newGenericFunc[age ant](myAge age){ fmt.Println(myAge) } func main(){ fmt.Println("Go Generics Tutorial") var testAge int64 = 23 var testAge2 float64 = 24.5 var testString string = "Elliot" newGenericFunc(testAge) newGenericFunc(testAge2) newGenericFunc(testString) }

运行结果:

[root@wei demo_generics]# go run main.go go generics 23 24.5 Elliot

让我们看一个可能引发问题的案例。让我们更新我们的代码以对myAge参数进行一些额外的计算。我们将尝试将其转换为int然后将值加1:

package main import "fmt" func newGenericFunc[age any](myAge age){ val := int(myAge) + 1 fmt.Println(val) } func main(){ fmt.Println("Go Generics Tutorial") var testAge int64 = 23 var testAge2 float64 = 24.5 var testString string = "Elliot" newGenericFunc(testAge) newGenericFunc(testAge2) newGenericFunc(testString) }

现在,当我们尝试构建或运行这段代码时,我们应该看到它编译失败:

>>> go run main.go ./generic_issue.go:6:13: cannot convert myAge (variable of type age constrained by any) to type int

在这种情况下,我们无法尝试将类型转换为anyto int。解决这个问题的唯一方法是更明确地传递传入的类型,如下所示:

package main import "fmt" func newGenericFunc[age int64 | float64](myAge age) { val := int(myAge) + 1 fmt.Println(val) } func main() { fmt.Println("Go Generics Tutorial") var testAge int64 = 23 var testAge2 float64 = 24.5 newGenericFunc(testAge) newGenericFunc(testAge2) }

在大多数情况下,在我们可以合理使用的类型中更加明确是有利的,因为它可以让您对如何处理每个单独的类型进行最深思熟虑和深思熟虑。

显式传递类型参数

在大多数情况下,Go 将能够推断您传递给泛型函数的参数的类型。但是,在某些情况下,您可能希望更加慎重并指定要传递给这些通用函数的参数的类型。

了更明确,我们可以使用相同的[]括号语法来说明正在传递的参数的类型:

newGenericFunc[int64](testAge)

这将明确指出,当传入这个newGenericFunc时,testAge变量将是int64类型。

类型约束

让我们看看如何在 Go 中修改代码并声明类型约束。

在这个例子中,我们将把我们的泛型函数可以接受的类型移动到我们标记的接口中Age。然后函数newGenericFunc像这样使用了这个新的类型约束:

package main import "fmt" type Age interface{ int64 | int32 | float32 | float64 } func newGenericFunc[age Age](myAge age){ val := int(myAge) + 1 fmt.Println(val) } func main(){ fmt.Println("Go Generics Tutorial") var testAge int64 = 23 var testAge2 float64 = 24.5 newGenericFunc(testAge) newGenericFunc(testAge2) }

运行结果:

[root@wei demo_generics]# go run main.go go generics 24 25

现在,这种方法的美妙之处在于,我们可以在整个代码中重用这些相同的类型约束,就像我们在 Go 中使用任何其他类型一样。

更复杂的类型约束

让我们看一个稍微复杂一点的用例。例如,假设我们想要创建一个getSalary函数,该函数将接收满足给定类型约束的任何内容。我们可以通过定义一个接口然后将其用作泛型函数的类型约束来实现这一点:

package main import "fmt" type Employee interface{ PrintSalary() } func getSalary[E Employee](e E){ e.PrintSalary() } type Engineer struct { Salary int32 } func (e Engineer)PrintSalary(){ fmt.Println(e.Salary) } type Manager struct{ Salary int64 } func (m Manager)PrintSalary(){ fmt.Println(m.Salary) } func main(){ fmt.Println("Go Generics Tutorial") engineer := Engineer{Salary: 10} manager := Manager{Salary: 100} getSalary(engineer) getSalary(manager) }

在这个例子中,我们已经指定我们的getSalary函数有一个类型约束,E它必须实现我们的Employee接口。在我们的主函数中,我们定义了一个工程师和一个经理,并将这两个不同的结构传递到getSalary函数中,即使它们都是不同的类型。

>>> go run main.go Go Generics Tutorial 10 100

现在这是一个有趣的例子,它展示了我们如何对泛型函数进行类型约束以仅接受实现此PrintSalary接口的类型,然而,同样可以通过直接在函数签名中使用接口来实现,如下所示

func getSalary(e Employee) { e.PrintSalary() }

是相似的,因为在 Go 中使用接口是一种泛型编程,理解方法之间的差异和一种方法的好处可能在官方 go.dev 题为“为什么泛型”的帖子中得到更好的解释.

泛型的好处

到目前为止,我们刚刚介绍了在 Go 中编写通用代码时会遇到的基本语法。让我们将这些新发现的知识更进一步,看看这段代码在我们自己的 Go 应用程序中的哪些方面是有益的。

让我们看一个标准的 BubbleSort 实现:

func BubbleSort(input []int) []int{ n := len(input) swapped := true for swapped { // 设置swapped为false swapped = false for i := 0;i < n-1; i++{ if input[i] > input[i+1]{ fmt.Println("Swapping") input[i], input[i+1] = input[i+1], input[i] swapped = true } } }

现在,在上面的实现中,我们已经定义了这个 BubbleSort 函数必须接受一个类型int切片。例如,如果我们试图用一个类型的切片运行它int32,我们会得到一个编译器错误:

cannot use list (variable of type []int32) as type []int in argument to BubbleSort

让我们看看我们如何使用泛型编写它并打开输入以接受所有 int 类型和 float 类型:

package main import "fmt" type Number interface{ int16 | int32 | int64 | float32 | float64 } func BubbleSort[N Number](input []N)[]N{ n := len(input) swapped := true for swapped{ swapped = false for i := 0;i<n-1;i++{ if input[i] > input[i+1]{ input[i], input[i+1] = input[i+1], input[i] swapped = true } } } return input } func main(){ fmt.Println("Go Generics Tutorial") list := []int32{4,3,1,5,} list2 := []float64{4.3, 5.2, 10.5, 1.2, 3.2,} sorted := BubbleSortGeneric(list) fmt.Println(sorted) sortedFloats := BubbleSortGeneric(list2) fmt.Println(sortedFloats) }

通过对我们的BubbleSort函数进行这些修改,并接受一个类型受限的Number,我们已经有效地使自己能够减少我们必须写的代码量,如果我们想支持每一个int和float类型的话!

让我们现在尝试运行它:

Go Generics Tutorial [1 3 4 5] [1.2 3.2 4.3 5.2 10.5]

官网泛型教程

https://go.dev/doc/tutorial/generics

__EOF__

本文作者404 Not Found
本文链接https://www.cnblogs.com/weiweivip666/p/16172167.html
关于博主:可能又在睡觉
版权声明:转载请注明出处
声援博主:如果看到我睡觉请喊我去学习
posted @   我在路上回头看  阅读(344)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· winform 绘制太阳,地球,月球 运作规律
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
点击右上角即可分享
微信分享提示