微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

Go1.17 初识泛型

最近,笔者在刷算法题时有这样的苦恼:算法题中会有很多的排序、比较题型,由于Go是强类型语言,就意味着需要针对不同的类型写出若干相同逻辑的代码,且重复度非常高。

就拿 int、float64 类型的两个数值比较大小来说,有几种写法。

1. 数值比较的几种写法

青铜 - 普通写法

func TwoIntNumMax(a, b int) int{

if a > b {

return a

}

return b

}

func TwoFloat64NumMax(a, b float64) float64{

if a > b {

return a

}

return b

}可以看出:除了类型不同,函数体中代码逻辑一模一样。然而,这里仅仅才是两种类型。假设,把所有的数值类型都写上一遍,那代码量也是不少。关键是作为有追求的程序员来说,岂能容忍这种做法。

白银 - 使用 interface 的写法

func TwoNumMax(a, b interface{}) (interface{}, error) {

ta := reflect.ValueOf(a)

tb := reflect.ValueOf(b)

switch ta.Kind() {

case reflect.Int:

if tb.Kind() != reflect.Int {

returnnil, ErrType

}

if ta.Int() > tb.Int() {

return a, nil

}

return b, nil

case reflect.Float64:

if tb.Kind() != reflect.Float64 {

returnnil, ErrType

}

if ta.Float() > tb.Float() {

return a, nil

}

return b, nil

default:

returnnil, ErrUnSupport

}

}

func TestMax(t *testing.T) {

r, err := TwoNumMax(1, 2)

if err != nil {

t.Fatal(err)

}

max := r.(int)

fmt.Println("max number is ", max)

}看似只提供了一个比较方法,但是进到该方法才会发现其中的复杂。如果把其他数值类型都写上的话,那么这个方法会变成一个巨无霸。这里使用 interface 相当于把每一种分开写的方法,糅合在了一个方法里面,结果可想而知。

鉴于以上,在写代码时,笔者感觉很痛苦:究其根源在于写出来的代码量大、重复度高、还不美观。那有没有其他可能?

王者 - 泛型写法

// 泛型类型约束,MinMaxAble 代表 多种类型

type MinMaxAble interface {

// 使用 type 来定义支持的类型

typeint, int8, int16, int32, int64,

uint, uint8, uint16, uint32, uint64,

float32, float64

}

// MinMaxAble 泛型类型约束

// T 泛型标识, 可以看做是代表了其支持的类型

func max[T MinMaxAble](a, b T) T {

if a > b {

return a

}

return b

}

func TestMax2(t *testing.T) {

// 写法1 使用 [int] 来明确指明 泛型的类型

maxnum := max[int](1, 2)

fmt.Println(maxnum)

// 写法2 不使用 [int] 来明确指明泛型的类型

// 此时 编译器自己会进行泛型类型推断

maxnum2 := max(1, 2)

fmt.Println(maxnum2)

maxnum3 := max[float64](1.1, 2.1)

fmt.Println(maxnum3)

maxnum4 := max(1.1, 2.1)

fmt.Println(maxnum4)

}似乎发现了了不起的事情!简简单单几行代码,实现了多种数值类型的数值比较,这是什么黑魔法?

对此,需要了解如下信息:

泛型将在 go1.18版本 开始正式支持泛型截止目前(2021/08/20)最新的 go1.17版本 中处于试验阶段go1.17版本 中开启泛型,需要添加 gcflagsgo run -gcflags=-G=3 ./main.go

通过 -gcflags=-G=3 在 go1.17 中开启泛型

go1.17版本 中泛型代码方法函数不可导出 (只能在当前包中使用)

2. 如何使用泛型

如果想在体验泛型乐趣,需要做如下步骤:

升级go版本到 1.17推荐使用 go 的多版本管理程序 gvm

https://github.com/moovweb/gvm

编写 泛型示例代码,编译运行时需要添加 gcflags使用最新版本 Goland IDE ,安装 go1.17 SDK

3. Go泛型示例代码

关于网上go泛型的示例代码,笔者这里推荐两个地方查看。

https://github.com/mattn/go-generics-example/blob/main/add/main.gogo1.17源码中 go1.17/src/go/types/testdata

总结

对于Go来说,泛型的出现是个必然结果。一方面可以简化代码逻辑,另一方面可以在编译时就能确认类型 (interface 在运行时才能确定类型),对于类型不匹配的情况,不至于在运行时才检测出来导致程序崩溃。

还有一点需要各位提前做好准备,等到 go1.18版本 之后,Go的标准库、各种知名库包以及开源程序,一定会基于泛型进行较大的改动。

路漫漫其修远兮吾将上下而求索,笔者相信Go的未来是光明的。

原文地址:https://www.toutiao.com/article/6998355143678755341/

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐