Go语言利用泛型封装常见的Map操作

2025-02-08 04:50

本文主要是介绍Go语言利用泛型封装常见的Map操作,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

《Go语言利用泛型封装常见的Map操作》Go语言在1.18版本中引入了泛型,这是Go语言发展的一个重要里程碑,它极大地增强了语言的表达能力和灵活性,本文将通过泛型实现封装常见的Map操作,感...

什么是泛型

泛型是一种编程范式,允许开发者在编写代码时定义通用的类型参数,而不是具体的类型。通过泛型,可以编写出能够处理多种数据类型的代码,而无需为每种类型重复编写相同的逻辑。例如,一个泛型函数可以同时处理整数、浮点数、字符串等多种类型的数据。

泛型解决了什么问题

在 Go 语言引入泛型之前,开发者在处理不同数据类型时,往往需要编写重复的代码。例如,实现一个排序算法,可能需要为整数、浮点数、字符串等分别编写不同的版本。这种重复不仅增加了代码量,也降低了代码的可维护性。引入泛型后,可以通过定义一个通用的类型参数,编写一个通用的排序函数,从而提高代码的复用性和可维护性。

Go泛型

Go 语言在 1.18 版本中引入了泛型,这是 Go 语言发展的一个重要里程碑,它极大地增强了语言的表达能力和灵活性。

基于泛型的常见Map操作

在上一篇文章里,我们使用Go泛型打造了一个优雅的切片工具库,本篇博客将利用Go泛型,封装常见的Map操作,并配套相应的单元测试。本篇博客所编写的代码,皆可直接集成到生产环境的公共代码库中。各位小伙伴可以根据自身项目的实际情况,将对你们项目有帮助的代码迁移到自己的项目当中。

1.获取map的所有keys

func GetMapKeys[K comparable, V any](m map[K]V) []K {
    keys := make([]K, 0, len(m))
    for k := range m {
       keys = append(keys, k)
    }
    return keys
}

2.根据过滤条件获取map的keys

func GetMapKeysMatchCondition[K comparable, V any](m map[K]V, condition func(K, V) bool) []K {
    keys := make([]K, 0, len(m))
    for k, v := range m {
       if condition(k, v) {
          keys = append(keys, k)
       }
    }
    return keys
}

3.获取map的所有values

func GetMapValues[K comparable, V any](m map[K]V) []V {
    values := make([]V, 0, len(m))
    for _, v := range m {
       values = append(values, v)
    }
    return values
}

4.根据过滤条件获取map的values

func GetMapValuesMatchCondition[K comparable, V any](m map[K]V, condition func(K, V) bool) []V {
    values := make([]V, 0, len(m))
    for k, v := range m {
       if condition(k, v) {
          values = append(values, v)
       }
    }
    return values
}

5.合并多个map

func MergeMaps[K comparable, V any](maps ...map[K]V) map[K]V {
    mergeMap := make(map[K]V)
    for _, m := range maps {
       for k, v := range m {
          mergeMap[k] = v
       }
    }
    return mergeMap
}

6.map转切片

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
}

7.切片转map

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
}

8.复制map

func CopyMap[K comparable, V any](oldMap map[K]V) map[K]V {
    newMap := make(map[K]V, len(oldMap))
    for k, v := range oldMap {
       newMap[k] = v
    }
    return newMap
}

9.sync.Map转map

func SyncMapToMap[K comparable, V any](syncMap sync.Map) map[K]V {
    m := make(map[K]V)
    syncMap.Range(func(key, value any) bool {
       // 尝试将key和value转换为指定的类型
       k, ok1 := key.(K)
       v, ok2 := value.(V)
       if ok1 && ok2 {
          m[k] =python v
       }
       return true
    })
    return m
}

10.map转sync.Map

func MapToSyncMap[K comparable, V any](m map[K]V) *sync.Map android{
    syncMap := &sync.Map{}
    if m == nil {
       return syncMap
    }
    for k, v := range m {
       syncMap.Store(k, v)
    }
    return syncMap
}

代码合集

我将上述所有代码集成到一个maps.go文件当中,并配套了单元测试文件maps_test.go。如果各位小伙伴们的项目有需要,只需将以下代码完整拷贝到你们项目的基础代码工具库即可。

maps.go

package maps

import (
    "sync"
)

// 获取map的所有keys
func GetMapKeys[K comparable, V any](m map[K]V) []K {
    keys := make([]K, 0, len(m))
    for k := range m {
       keys = append(keys, k)
    }
    return keys
}

// 根据过滤条件获取map的keys
func GetMapKeysMatchCondition[K comparable, V any](m map[K]V, condition func(K, V) bool) []K {
    keys := make([]K, 0, len(m))
    for k, v := range m {
       if condition(k, v) {
          keys = append(keys, k)
       }
    }
    return keys
}

func GetMapValues[K comparable, V any](m map[K]V) []V {
    values := make([]V, 0, len(m))
    for _, v := range m {
       values = append(values, v)
    }
    return values
}

// 根据过滤条件获取map的values
func GetMapValuesMatchCondition[K comparable, V any](m map[K]V, condition func(K, V) bool) []V {
    values :China编程= make([]V, 0, len(m))
    for k, v := range m {
       if condition(k, v) {
          values = append(values, v)
       }
    }
    return values
}

// 合并多个map
func MergeMaps[K comparable, V any](maps ...map[K]V) map[K]V {
    mergeMap := make(map[K]V)
    for _, m := range maps {
       for k, v := range m {
          mergeMap[k] = v
       }
    }
    return mergeMap
}

// map转切片
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
}

// 切片转map
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
}

// 复制map
func CopyMap[K comparable, V any](oldMap map[K]V) map[K]V {
    newMap := make(map[K]V, len(oldMap))
    for k, v := range oldMap {
       newMap[k] = v
    }
    return newMap
}

// sync.Map转map
func SyncMapToMap[K comparable, V any](syncMap sync.Map) map[K]V {
    m := make(map[K]V)
    syncMap.Range(func(key, value any) bool {
       // 尝试将key和value转换为指定的类型
       k, ok1 := key.(K)
       v, ok2 := value.(V)
       if ok1 && ok2 {
          m[k] = v
       }
       return true
    })
 python   return m
}

func MapToSyncMap[K comparable, V any](m map[K]V) *sync.Map {
    syncMap := &sync.Map{}
    if m == nil {
       return syncMap
    }
    for k, v := range m {
       syncMap.Store(k, v)
    }
    return syncMap
}

maps_test.go

package maps

import (
    "sync"
    "testing"
)

// 测试 GetMapKeys 函数
func TestGetMapKeys(t *testing.T) {
    m := map[string]int{
       "apple":  1,
       "banana": 2,
       "cherry": 3,
    }
    keys := GetMapKeys(m)
    if len(keys) != len(m) {
       t.Errorf("Expected %d keys, got %d", len(m), len(keys))
    }
    for _, k := range keys {
       if _, exists := m[k]; !exists {
          t.Errorf("Key %s not found in original map", k)
       }
    }
}

// 测试 GetMapKeysMatchCondition 函数
func TestGetMapKeysMatchCondition(t *testing.T) {
    m := map[string]int{
       "apple":  1,
       "banana": 2,
       "cherry": 3,
    }
    condition := func(k string, v int) bool {
       return v > 1
    }
    keys := GetMapKeysMatchCondition(m, condition)
    for _, k := range keys {
       if m[k] <= 1 {
          t.Errorf("Key %s should not be included as its value is not greater than 1", k)
       }
    }
}

// 测试 GetMapValues 函数
func TestGetMapValues(t *testing.T) {
    m := map[string]int{
       "apple":  1,
       "banana": 2,
       "cherry": 3,
    }
    values := GetMapValues(m)
    if len(values) != len(m) {
       t.Errorf("Expected %d values, got %d", len(m), len(values))
    }
    valueSet := make(map[int]bool)
    for _, v := range values {
       valueSet[v] = true
    }
    for _, v := range m {
       if !valueSet[v] {
          t.Errorf("Value %d not found in result values", v)
       }
    }
}

// 测试 GetMapValuesMatchCondition 函数
func TestGetMapValuesMatchCondition(t *testing.T) {
    m := map[string]int{
       "apple":  1,
       "banana": 2,
       "cherry": 3,
    }
    condition := func(k string, v int) bool {
       return v > 1
    }
    values := GetMapValuesMatchCondition(m, condition)
    for _, v := range values {
       if v <= 1 {
          t.Errorf("Value %d should not be included as it is not greater than 1", v)
       }
    }
}

// 测试 MergeMaps 函数
func TestMergeMaps(t *testing.T) {
    m1 := map[string]int{
       "apple":  1,
       "banana": 2,
    }
    m2 := map[string]int{
       "banana": 3,
       "cherry": 4,
    }
    merged := MergeMaps(m1, m2)
    for k := range m1 {
       if _, exists := merged[k]; !exists {
          t.Errorf("key %s not exist in m1", k)
       }
    }
    for k := range m2 {
       if _, exists := merged[k]; !exists {
          t.Errorf("key %s not exist in m2", k)
       }
    }
}

// 测试 MapToSlice 函数
func TestMapToSlice(t *testing.T) {
    m := map[string]int{
       "apple":  1,
       "banana": 2,
       "cherry": 3,
    }
    extractor := func(v int) int {
     js  return v * 2
    }
    slice := MapToSlice(m, extractor)
    if len(slice) != len(m) {
       t.Errorf("Expected %d elements in slice, got %d", len(m), len(slice))
    }
    for _, v := range m {
       found := false
       for _, s := range slice {
          if s == v*2 {
             found = true
             break
          }
       }
       if !found {
          t.Errorf("Transformed value %d not found in slice", v*2)
       }
    }
}

// 测试 SliceToMap 函数
func TestSliceToMap(t *testing.T) {
    s := []int{1, 2, 3}
    keyFunc := func(v int) int {
       return v * 10
    }
    m := SliceToMap(s, keyFunc)
    if len(m) != len(s) {
       t.Errorf("Expected %d keys in map, got %d", len(s), len(m))
    }
    for _, v := range s {
       key := keyFunc(v)
       if val, exists := m[key]; !exists || val != v {
          t.Errorf("Value for key %d in map does not match original slice", key)
       }
    }
}

// 测试 CopyMap 函数
func TestCopyMap(t *testing.T) {
    oldMap := map[string]int{
       "apple":  1,
       "banana": 2,
       "cherry": 3,
    }
    newMap := CopyMap(oldMap)
    if len(newMap) != len(oldMap) {
       t.Errorf("Expected %d keys in new map, got %d", len(oldMap), len(newMap))
    }
    for k, v := range oldMap {
       if val, exists := newMap[k]; !exists || val != v {
          t.Errorf("Value for key %s in new map does not match original map", k)
       }
    }
}

// 测试 SyncMapToMap 函数
func TestSyncMapToMap(t *testing.T) {
    var syncMap sync.Map
    syncMap.Store("apple", 1)
    syncMap.Store("banana", 2)
    syncMap.Store("cherry", 3)
    m := SyncMapToMap[string, int](syncMap)
    syncMap.Range(func(key, value any) bool {
       k := key.(string)
       v := value.(int)
       if val, exists := m[k]; !exists || val != v {
          t.Errorf("Value for key %s in map does not match sync.Map", k)
       }
       return true
    })
}

// 测试 MapToSyncMap 函数
func TestMapToSyncMap(t *testing.T) {
    m := map[string]int{
       "apple":  1,
       "banana": 2,
       "cherry": 3,
    }
    syncMap := MapToSyncMap(m)
    for k, v := range m {
       value, exists := syncMap.Load(k)
       if !exists || value.(int) != v {
          t.Errorf("Value for key %s in sync.Map does not match original map", k)
       }
    }
}

总结

本文使用Go泛型,对常见的Map操作进行了封装,整理出了一个Map工具库maps.go

以上就是Go语言利用泛型封装常见的Map操作的详细内容,更多关于Go泛型封装Map操作的资料请关注China编程(www.chinasem.cn)其它相关文章!

这篇关于Go语言利用泛型封装常见的Map操作的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1153336

相关文章

C#中的 Dictionary常用操作

《C#中的Dictionary常用操作》C#中的DictionaryTKey,TValue是用于存储键值对集合的泛型类,允许通过键快速检索值,并且具有唯一键、动态大小和无序集合的特性,常用操作包括添... 目录基本概念Dictionary的基本结构Dictionary的主要特性Dictionary的常用操作

C# winform操作CSV格式文件

《C#winform操作CSV格式文件》这篇文章主要为大家详细介绍了C#在winform中的表格操作CSV格式文件的相关实例,文中的示例代码讲解详细,感兴趣的小伙伴可以参考一下... 目录实例一实例效果实现代码效果展示实例二实例效果完整代码实例一实例效果当在winform界面中点击读取按钮时 将csv中

前端bug调试的方法技巧及常见错误

《前端bug调试的方法技巧及常见错误》:本文主要介绍编程中常见的报错和Bug,以及调试的重要性,调试的基本流程是通过缩小范围来定位问题,并给出了推测法、删除代码法、console调试和debugg... 目录调试基本流程调试方法排查bug的两大技巧如何看控制台报错前端常见错误取值调用报错资源引入错误解析错误

Golang基于内存的键值存储缓存库go-cache

《Golang基于内存的键值存储缓存库go-cache》go-cache是一个内存中的key:valuestore/cache库,适用于单机应用程序,本文主要介绍了Golang基于内存的键值存储缓存库... 目录文档安装方法示例1示例2使用注意点优点缺点go-cache 和 Redis 缓存对比1)功能特性

Golang中map缩容的实现

《Golang中map缩容的实现》本文主要介绍了Go语言中map的扩缩容机制,包括grow和hashGrow方法的处理,具有一定的参考价值,感兴趣的可以了解一下... 目录基本分析带来的隐患为什么不支持缩容基本分析在 Go 底层源码 src/runtime/map.go 中,扩缩容的处理方法是 grow

Go 1.23中Timer无buffer的实现方式详解

《Go1.23中Timer无buffer的实现方式详解》在Go1.23中,Timer的实现通常是通过time包提供的time.Timer类型来实现的,本文主要介绍了Go1.23中Timer无buff... 目录Timer 的基本实现无缓冲区的实现自定义无缓冲 Timer 实现更复杂的 Timer 实现总结在

基于Python实现多语言朗读与单词选择测验

《基于Python实现多语言朗读与单词选择测验》在数字化教育日益普及的今天,开发一款能够支持多语言朗读和单词选择测验的程序,对于语言学习者来说无疑是一个巨大的福音,下面我们就来用Python实现一个这... 目录一、项目概述二、环境准备三、实现朗读功能四、实现单词选择测验五、创建图形用户界面六、运行程序七、

Go使用pprof进行CPU,内存和阻塞情况分析

《Go使用pprof进行CPU,内存和阻塞情况分析》Go语言提供了强大的pprof工具,用于分析CPU、内存、Goroutine阻塞等性能问题,帮助开发者优化程序,提高运行效率,下面我们就来深入了解下... 目录1. pprof 介绍2. 快速上手:启用 pprof3. CPU Profiling:分析 C

使用Go语言开发一个命令行文件管理工具

《使用Go语言开发一个命令行文件管理工具》这篇文章主要为大家详细介绍了如何使用Go语言开发一款命令行文件管理工具,支持批量重命名,删除,创建,移动文件,需要的小伙伴可以了解下... 目录一、工具功能一览二、核心代码解析1. 主程序结构2. 批量重命名3. 批量删除4. 创建文件/目录5. 批量移动三、如何安

通俗易懂的Java常见限流算法具体实现

《通俗易懂的Java常见限流算法具体实现》:本文主要介绍Java常见限流算法具体实现的相关资料,包括漏桶算法、令牌桶算法、Nginx限流和Redis+Lua限流的实现原理和具体步骤,并比较了它们的... 目录一、漏桶算法1.漏桶算法的思想和原理2.具体实现二、令牌桶算法1.令牌桶算法流程:2.具体实现2.1