什么是泛型
泛型是一种编程范式,允许开发者在编写代码时定义通用的类型参数,而不是具体的类型。通过泛型,可以编写出能够处理多种数据类型的代码,而无需为每种类型重复编写相同的逻辑。例如,一个泛型函数可以同时处理整数、浮点数、字符串等多种类型的数据。
泛型解决了什么问题
在 go 语言引入泛型之前,开发者在处理不同数据类型时,往往需要编写重复的代码。例如,实现一个排序算法,可能需要为整数、浮点数、字符串等分别编写不同的版本。这种重复不仅增加了代码量,也降低了代码的可维护性。引入泛型后,可以通过定义一个通用的类型参数,编写一个通用的排序函数,从而提高代码的复用性和可维护性。
基于泛型的常见切片操作
博主结合自身在实际开发当中的经验,将利用go泛型,封装一些常见的切片操作。本篇博客所编写的代码,皆可直接集成到生产环境的公共代码库中。各位小伙伴可以根据自身项目的实际情况,将对你们项目有帮助的代码迁移到自己的项目当中。
1.反转切片(改变原切片)
func reverseoriginalslice[t any](s []t) {
for i, j := 0, len(s)-1; i < j; i, j = i+1, j-1 {
s[i], s[j] = s[j], s[i]
}
}
2.反转切片(不改变原切片)
func reverseslice[t any](s []t) []t {
res := make([]t, len(s))
copy(res, s)
reverseoriginalslice(res) // 调用之前的reverseoriginalslice函数
return res
}
3.切片分批
func batchslice[t any](s []t, size int) [][]t {
var batchslice [][]t
// 遍历切片,每次取 size 个元素
for i := 0; i < len(s); i += size {
end := i + size
// 处理最后一批元素数量不足 size 的情况
if end > len(s) {
end = len(s)
}
// 将当前批次的元素添加到结果中
batchslice = append(batchslice, s[i:end])
}
return batchslice
}
4.合并切片
func mergeslices[t any](slices ...[]t) []t {
totallength := 0
for _, slice := range slices {
totallength += len(slice)
}
res := make([]t, 0, totallength)
for _, slice := range slices {
ls := make([]t, len(slice))
copy(ls, slice)
res = append(res, ls...)
}
return res
}
5.切片去重
func uniqueslice[t comparable](s []t) []t {
seen := make(map[t]bool)
res := make([]t, 0, len(s))
for _, v := range s {
if !seen[v] {
// 如果元素未出现过,添加到结果切片中
res = append(res, v)
seen[v] = true
}
}
return res
}
6.切片转哈希表
func slicetomap[t any, k comparable](s []t, keyfunc func(t) k) map[k]t {
res := make(map[k]t)
for _, v := range s {
key := keyfunc(v)
res[key] = v
}
return res
}
7.哈希表转切片
func maptoslice[k comparable, v any, t any](m map[k]v, extractor func(v) t) []t {
res := make([]t, 0, len(m))
for _, v := range m {
res = append(res, extractor(v))
}
return res
}
8.获取切片元素的某个字段
func getlistfield[t any, v any](s []t, fieldfunc func(t) v) []v {
res := make([]v, 0, len(s))
for _, item := range s {
res = append(res, fieldfunc(item))
}
return res
}
9.切片全部元素满足条件判断
func slicematchcondition[t any](s []t, condition func(t) bool) bool {
for _, v := range s {
if !condition(v) {
return false
}
}
return true
}
10.取切片交集
func intersection[t comparable](slices ...[]t) []t {
if len(slices) == 0 {
return nil
}
// 使用 map 来存储第一个切片中的元素
intersectionmap := make(map[t]int)
for _, v := range slices[0] {
intersectionmap[v]++
}
// 遍历后续切片,更新交集
for _, slice := range slices[1:] {
m := make(map[t]int)
for _, v := range slice {
if _, exists := intersectionmap[v]; exists {
m[v]++
}
}
intersectionmap = m
}
// 将交集的元素收集到结果切片中
var res []t
for k := range intersectionmap {
res = append(res, k)
}
return res
}
11.取切片并集
func union[t comparable](slices ...[]t) []t {
elementmap := make(map[t]struct{})
for _, slice := range slices {
for _, v := range slice {
elementmap[v] = struct{}{}
}
}
var res []t
for k := range elementmap {
res = append(res, k)
}
return res
}
代码合集
我将上述所有代码集成到一个slices.go文件当中。如果各位小伙伴们的项目有需要,只需将以下代码完整拷贝到你们项目的基础代码工具库即可。
slices.go
package slices
// 反转切片(改变原切片)
func reverseoriginalslice[t any](s []t) {
for i, j := 0, len(s)-1; i < j; i, j = i+1, j-1 {
s[i], s[j] = s[j], s[i]
}
}
// 反钻切片(不改变原切片)
func reverseslice[t any](s []t) []t {
res := make([]t, len(s))
copy(res, s)
reverseoriginalslice(res)
return res
}
// 切片分批
func batchslice[t any](s []t, size int) [][]t {
var batchslice [][]t
for i := 0; i < len(s); i += size {
end := i + size
if end > len(s) {
end = len(s)
}
batchslice = append(batchslice, s[i:end])
}
return batchslice
}
// 合并切片
func mergeslices[t any](slices ...[]t) []t {
totallength := 0
for _, slice := range slices {
totallength += len(slice)
}
res := make([]t, 0, totallength)
for _, slice := range slices {
ls := make([]t, len(slice))
copy(ls, slice)
res = append(res, ls...)
}
return res
}
// 切片去重
func uniqueslice[t comparable](s []t) []t {
seen := make(map[t]bool)
res := make([]t, 0, len(s))
for _, v := range s {
if !seen[v] {
res = append(res, v)
seen[v] = true
}
}
return res
}
// 切片转哈希表
func slicetomap[t any, k comparable](s []t, keyfunc func(t) k) map[k]t {
res := make(map[k]t)
for _, v := range s {
key := keyfunc(v)
res[key] = v
}
return res
}
// 哈希表转切片
func maptoslice[k comparable, v any, t any](m map[k]v, extractor func(v) t) []t {
res := make([]t, 0, len(m))
for _, v := range m {
res = append(res, extractor(v))
}
return res
}
// 获取切片元素的某个字段
func getlistfield[t any, v any](s []t, fieldfunc func(t) v) []v {
res := make([]v, 0, len(s))
for _, item := range s {
res = append(res, fieldfunc(item))
}
return res
}
// 切片全部元素满足条件判断
func slicematchcondition[t any](s []t, condition func(t) bool) bool {
for _, v := range s {
if !condition(v) {
return false
}
}
return true
}
// 取切片交集
func intersection[t comparable](slices ...[]t) []t {
if len(slices) == 0 {
return nil
}
intersectionmap := make(map[t]int)
for _, v := range slices[0] {
intersectionmap[v]++
}
for _, slice := range slices[1:] {
m := make(map[t]int)
for _, v := range slice {
if _, exists := intersectionmap[v]; exists {
m[v]++
}
}
intersectionmap = m
}
var res []t
for k := range intersectionmap {
res = append(res, k)
}
return res
}
// 取切片并集
func union[t comparable](slices ...[]t) []t {
elementmap := make(map[t]struct{})
for _, slice := range slices {
for _, v := range slice {
elementmap[v] = struct{}{}
}
}
var res []t
for k := range elementmap {
res = append(res, k)
}
return res
}
总结
本文使用go泛型,对常见的切片操作进行了封装,整理出了一个切片工具库slices.go。
到此这篇关于go语言泛型打造优雅的切片工具库的文章就介绍到这了,更多相关go泛型内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论