Go泛型-牛刀小试

2022年3月18日 263点热度 0人点赞 0条评论

图片

升级Go版本到 1.18

    下载地址:GO1.18

问题所在

    相信有过其他语言编程基础的人,对于以下代码肯定看不下去:

    以下代码来源与golang官网:https://go.dev/doc/tutorial/generics

package main
import "fmt"
func SumInts(m map[string]int64) int64 { var s int64 for _, v := range m { s += v } return s}
func SumFloats(m map[string]float64) float64 { var s float64 for _, v := range m { s += v } return s}
func main() { ints := map[string]int64{ "first": 34, "second": 56, }
floats := map[string]float64{ "first": 35.98, "second": 43.8, }
sumInts := SumInts(ints) sumFloats := SumFloats(floats) fmt.Println("结果:", sumInts, sumFloats)}

蛋疼的临时解决方案

    在Go1.18之前也不是没有办法解决,可以使用接口类型实现:

func SumIntOrFloats(m map[string]interface{}) (int64, float64) {  var s1 int64  var s2 float64  for _, v := range m {    switch v.(type) {    case int64:      vint := v.(int64)      s1 += vint    case float64:      vfloat := v.(float64)      s2 += vfloat    }  }  return s1, s2}

以上代码写的也很别扭,还不如多写一个方法,反而更简单一些,你如果有其他更简单的实现方式也可以留言。


型终于来了--被放鸽子多次之后

    直接上代码:

package main
import "fmt"
//类型参数约束type comparable interface { ~string | ~int64 | ~float64}
func SumIntsOrFloats[K comparable, V int64 | float64](m map[K]V) V { var s V for _, v := range m { s += v } return s}
func main() { ints := map[string]int64{ "first": 34, "second": 56, }
floats := map[string]float64{ "first": 35.98, "second": 43.8, }
orFloats := SumIntsOrFloats(ints) intsOrFloats := SumIntsOrFloats(floats) fmt.Println("结果:", orFloats, intsOrFloats)}

类型参数

    看了以上泛型代码,没错这就是Go的泛型语法

func SumIntsOrFloats[K comparable, V int64 | float64](m map[K]V) V
func 方法名[类型参数](形式参数)返回值

简单案例

//这里类型参数限制,Max方法可以接收int64以及float64类型的参数func Max[T int64 | float64](a, b T) T {  if a >= b {    return a  }  return b}
func main(){ var a int64 = 1 var b int64 = 2 //这里调用的时候参数类型必须一致,a,b类型要么int64要么都是float64 res := Max(a, b) fmt.Println(res)
var c float64 = 1.1 var d float64 = 2.1 res1 := Max(c, d) fmt.Println(res1)}

类型参数约束

    类型参数约束条件简单表示形式

1,直接写在 [] 中

Max[T int64 | float64]

2,定义约束接口 Number

type Number interface {  int64 | float64}
func Max[T Number](a, b T) T { if a >= b { return a } return b}

3,标准库内置的类型参数约束

any

// any is an alias for interface{} and is equivalent to interface{} in all ways.// any其实就是一个空接口,所有类型,也就是没有约束type any = interface{}

func useAny[T any](t T) T { return t}

comparable

// comparable is an interface that is implemented by all comparable types// (booleans, numbers, strings, pointers, channels, arrays of comparable types,// structs whose fields are all comparable types).// The comparable interface may only be used as a type parameter constraint,// not as the type of a variable.// 可比较类型,只能用于泛型约束条件中,不能当作变量类型使用type comparable interface{ comparable }
func useComparable[T comparable](t T) T { return t}

关于内置的comparable不清楚为啥在map key的约束中不能使用,以下使用了自己定义的comparable约束,但是使用Go内置的comparable直接飘红了

//参数约束type comparable interface {  ~string | ~int64 | ~float64}
func SumIntsOrFloats[K comparable, V int64 | float64](m map[K]V) V

图片

constraints

非标准库的泛型约束,在Go1.18的beta版本中Go开发者其实有把constraints放到标准库中,后面考虑到最佳实践问题,具体需不需要constraints包中的约束就交给用户去实践,因此放在了exp包下 golang.org/x/exp/constraints

package constraints

type Signed interface { ~int | ~int8 | ~int16 | ~int32 | ~int64}

type Unsigned interface { ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr}

type Integer interface { Signed | Unsigned}

type Float interface { ~float32 | ~float64}

type Complex interface { ~complex64 | ~complex128}

type Ordered interface { Integer | Float | ~string}

关于泛型约束还有很多其他的写法,这里就不做展开,先介绍简单的使用方式,后续在慢慢深入讲解。

总结


1,本文讲解了没有泛型时写通用代码遇到的问题

2,简单泛型的使用方式

3,泛型类型参数

4,类型参数约束

5,内置的参数约束

6,非标准库的泛型参数约束

参考链接:

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

80340Go泛型-牛刀小试

这个人很懒,什么都没留下

文章评论