golang泛型:generics

使用非泛型函数

golang在没有泛型的时候,如果我们要计算一个map的所有value之和,比如该map的key为string类型,value是int64类型,我们需要定义以下函数:

// SumInts adds together the values of m.
func SumInts(m map[string]int64) int64 {
    var s int64
    for _, v := range m {
        s += v
    }
    return s
}

同时我们又有另外一个map也需要计算所有value之和,该map的key也为string类型,但是value是float64类型,所以我们还需要定义另外一个函数:

// SumFloats adds together the values of m.
func SumFloats(m map[string]float64) float64 {
    var s float64
    for _, v := range m {
        s += v
    }
    return s
}

然后在分别调用两个函数执行计算操作

1. 先定义两个map

// Initialize a map for the integer values
ints := map[string]int64{
    "first": 34,
    "second": 12,
}

// Initialize a map for the float values
floats := map[string]float64{
	"first": 35.98,
	"second": 26.99,
}

2. 调用函数

fmt.Printf("Non-Generic Sums: %v and %v\n",
        SumInts(ints),
        SumFloats(floats))

可以发现SumInts和SumFloats除了接收参数不同之外内部逻辑完全相同,如果有更多参数类型不不同但功能逻辑完全的功能,会发现到处都是重复的代码,所以就有了泛型来解决这个问题

使用泛型函数

定义泛型函数

实现同样的计算一个map的value之和,可以定义如下函数:

// SumIntsOrFloats sums the values of map m. It supports both int64 and float64
// as types for map values.
func SumIntsOrFloats[K comparable, V int64 | float64](m map[K]V) V {
	var s V
	for _, v := range m {
		s += v
	}
	return s
}
  • 该函数声明了两个类型参数,即[]中的K和V,和一个要使用这两个类型参数的map类型的参数m,返回一个V类型的值
  • 其中comparable是一个在go里面预定义的类型,表示K这个参数需要支持== 和 != 操作
  • 所以可理解为该函数接收一个map参数,该map的key是一个comparable类型的值,value是int64或者float类型的值,所以定义一个map[int]int64也是可以用这个函数计算的,因为int类型也是一个comparable类型的参数,可以做==和!=操作

调用函数

fmt.Printf("Generic Sums: %v and %v\n",
		SumIntsOrFloats[string, int64](ints),
		SumIntsOrFloats[string, float64](floats))

一个函数就解决了问题,如果还要添加int类型,float类型或者其他类型,也只不过是在[]中再添加对应的类型即可,并不需要另外重写一个函数

类型推导

go编译器在调用泛型函数时会自动推导出参数类型,所以调用泛型函数时可以省略传入参数类型

调用函数

fmt.Printf("Generic Sums, type parameters inferred: %v and %v\n",
		SumIntsOrFloats(ints),
		SumIntsOrFloats(floats))

声明类型约束

在[]中定义了一个V的类型参数,当只有几个类型时看着还比较清晰,如果类型很多,比如float,float64,int,int64,int32等等等等,看着不是那么清晰了,所以可以声明一个类型约束,定义一个Number类型的interface,类型为int64或float64,如果有其他类型可以一直在后面加

1. 定义类型约束

type Number interface {
	int64 | float64
}

2. 使用类型约束

// SumNumbers sums the values of map m. It supports both integers
// and floats as map values.
func SumNumbers[K comparable, V Number](m map[K]V) V {
	var s V
	for _, v := range m {
		s += v
	}
	return s
}

3. 调用函数

fmt.Printf("Generic Sums with Constraint: %v and %v\n",
		SumNumbers(ints),
		SumNumbers(floats))

总结

泛型是为了解决出现太多重复代码问题,最佳实践如下:

1. 给包含很多类型的变量声明类型约束,直接在泛型函数中使用该类型约束

2. 调用泛型函数时不必添加类型

附全文代码:

package main

import "fmt"

type Number interface {
	int64 | float64
}

func main() {
	// Initialize a map for the integer values
	ints := map[string]int64{
		"first":  34,
		"second": 12,
	}

	// Initialize a map for the float values
	floats := map[string]float64{
		"first":  35.98,
		"second": 26.99,
	}

	intsInts := map[int]int64{
	    0: 10,
		1: 20,
	}

	fmt.Printf("Non-Generic Sums: %v and %v\n",
		SumInts(ints),
		SumFloats(floats))

	fmt.Printf("Generic Sums: %v and %v\n",
		SumIntsOrFloats[string, int64](ints),
		SumIntsOrFloats[string, float64](floats))

	fmt.Printf("Generic Sums, type parameters inferred: %v and %v\n",
		SumIntsOrFloats(ints),
		SumIntsOrFloats(floats))

	fmt.Printf("Generic Sums with Constraint: %v and %v and %v\n",
		SumNumbers(ints),
		SumNumbers(floats),
        SumNumbers(intsInts))
}

// SumInts adds together the values of m.
func SumInts(m map[string]int64) int64 {
	var s int64
	for _, v := range m {
		s += v
	}
	return s
}

// SumFloats adds together the values of m.
func SumFloats(m map[string]float64) float64 {
	var s float64
	for _, v := range m {
		s += v
	}
	return s
}

// SumIntsOrFloats sums the values of map m. It supports both int64 and float64
// as types for map values.
func SumIntsOrFloats[K comparable, V int64 | float64](m map[K]V) V {
	var s V
	for _, v := range m {
		s += v
	}
	return s
}

// SumNumbers sums the values of map m. It supports both integers
// and floats as map values.
func SumNumbers[K comparable, V Number](m map[K]V) V {
	var s V
	for _, v := range m {
		s += v
	}
	return s
}

执行结果如下: 

$ go run generic.go 
Non-Generic Sums: 46 and 62.97
Generic Sums: 46 and 62.97
Generic Sums, type parameters inferred: 46 and 62.97
Generic Sums with Constraint: 46 and 62.97 and 30

参考

Tutorial: Getting started with generics - The Go Programming Language

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值