引言
Go 1.18 版本引入了泛型支持,这为我们的代码带来了更多的灵活性和复用性。本文将介绍如何利用 Go 1.18 的泛型特性,创建一个高效且实用的工具函数库。
为什么需要泛型?
在没有泛型的情况下,我们经常需要为不同类型的切片编写类似的函数,这会导致代码冗余和维护困难。泛型允许我们编写通用的函数,处理多种类型的数据,从而减少重复代码,提高代码的可读性和可维护性。
工具函数库介绍
我们将创建一个名为 tools 的包,其中包含以下几个常用的工具函数:
- InSlice:检查元素是否存在于切片中。
- SliceToMapByField:将对象切片转换为 map,键值对为指定字段和对象。
- SliceToMapsByField:将对象切片转换为 map 数组,键值对为指定字段和对象数组。
- DiffLists:比较两个切片,返回新增、删除和共同拥有的元素。
1. InSlice
InSlice 函数用于检查一个元素是否存在于切片中。通过泛型的支持,我们可以轻松地处理不同类型的切片。
package tools
// InSlice 检查元素是否存在于切片中
func InSlice[K comparable](slice []K, key K) bool {
for _, v := range slice {
if v == key {
return true
}
}
return false
}
2. SliceToMapByField
SliceToMapByField 函数将对象切片转换为 map,键值对为指定字段和对象。这个函数在处理数据转换时非常有用,特别是在处理数据库查询结果时。
package tools
// SliceToMapByField 将对象切片转换为 map,键值对为指定字段和对象
func SliceToMapByField[T any, K comparable](slice []T, keyFunc func(T) K) map[K]T {
result := make(map[K]T)
for _, v := range slice {
key := keyFunc(v)
result[key] = v
}
return result
}
3. SliceToMapsByField
SliceToMapsByField 函数将对象切片转换为 map 数组,键值对为指定字段和对象数组。这个函数在处理多对一关系的数据时非常有用。
package tools
// SliceToMapsByField 将对象切片转换为 map 数组,键值对为指定字段和对象数组
func SliceToMapsByField[T any, K comparable](slice []T, fieldFunc func(T) K) map[K][]T {
result := make(map[K][]T)
for _, v := range slice {
key := fieldFunc(v)
result[key] = append(result[key], v)
}
return result
}
4. DiffLists
DiffLists 函数接收两个切片 a 和 b,返回三个切片: 第一个切片包含 b 中但不在 a 中的元素,用于新增。 第二个切片包含 a 中但不在 b 中的元素,用于删除。 第三个切片包含 a 和 b 共同拥有的元素,用于编辑。
package tools
// DiffLists 比较两个切片,返回新增、删除和共同拥有的元素
func DiffLists[T comparable](a, b []T) (added, deleted, edited []T) {
bMap := make(map[T]bool)
for _, item := range b {
bMap[item] = true
}
for _, item := range a {
if _, found := bMap[item]; found {
edited = append(edited, item)
} else {
deleted = append(deleted, item)
}
}
for item := range bMap {
if !InSlice(a, item) {
added = append(added, item)
}
}
return added, deleted, edited
}
使用示例
下面是一些使用这些工具函数的示例代码,帮助你更好地理解和应用它们。
package main
import (
"fmt"
"your_project/tools"
)
type User struct {
ID int
Name string
}
func main() {
// InSlice 示例
intSlice := []int{1, 2, 3, 4, 5}
fmt.Println(tools.InSlice(intSlice, 3)) // 输出: true
// SliceToMapByField 示例
users := []User{
{ID: 1, Name: "Alice"},
{ID: 2, Name: "Bob"},
{ID: 3, Name: "Charlie"},
}
userMap := tools.SliceToMapByField(users, func(u User) int { return u.ID })
fmt.Println(userMap) // 输出: map[1:{1 Alice} 2:{2 Bob} 3:{3 Charlie}]
// SliceToMapsByField 示例
usersWithSameID := []User{
{ID: 1, Name: "Alice"},
{ID: 1, Name: "Alice2"},
{ID: 2, Name: "Bob"},
}
userMaps := tools.SliceToMapsByField(usersWithSameID, func(u User) int { return u.ID })
fmt.Println(userMaps) // 输出: map[1:[{1 Alice} {1 Alice2}] 2:[{2 Bob}]]
// DiffLists 示例
listA := []int{1, 2, 3, 4}
listB := []int{3, 4, 5, 6}
added, deleted, edited := tools.DiffLists(listA, listB)
fmt.Println("Added:", added) // 输出: Added: [5 6]
fmt.Println("Deleted:", deleted) // 输出: Deleted: [1 2]
fmt.Println("Edited:", edited) // 输出: Edited: [3 4]
}
如果你觉得这篇文章对你有帮助,不妨点个赞,让更多的人看到它吧!