您的位置 首页 golang

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

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

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

  1. 泛型将在 go1.18版本 开始正式支持
  2. 泛型截止目前(2021/08/20)最新的 go1.17版本 中处于试验阶段
  3. go1.17版本 中 开启泛型 ,需要添加 gcflags
  1. go1.17版本 中泛型代码方法或函数不可导出 (只能在当前包中使用)

2. 如何使用泛型

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

  1. 升级go版本到 1.17

推荐使用 go 的多版本管理程序 gvm

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

3. Go泛型示例代码

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

  1. go1.17源码中 go1.17/src/go/types/testdata

总结

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

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

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

文章来源:智云一二三科技

文章标题:Go1.17 初识泛型

文章地址:https://www.zhihuclub.com/98729.shtml

关于作者: 智云科技

热门文章

网站地图