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

相关文章

使用Java将各种数据写入Excel表格的操作示例

《使用Java将各种数据写入Excel表格的操作示例》在数据处理与管理领域,Excel凭借其强大的功能和广泛的应用,成为了数据存储与展示的重要工具,在Java开发过程中,常常需要将不同类型的数据,本文... 目录前言安装免费Java库1. 写入文本、或数值到 Excel单元格2. 写入数组到 Excel表格

Python中pywin32 常用窗口操作的实现

《Python中pywin32常用窗口操作的实现》本文主要介绍了Python中pywin32常用窗口操作的实现,pywin32主要的作用是供Python开发者快速调用WindowsAPI的一个... 目录获取窗口句柄获取最前端窗口句柄获取指定坐标处的窗口根据窗口的完整标题匹配获取句柄根据窗口的类别匹配获取句

Python位移操作和位运算的实现示例

《Python位移操作和位运算的实现示例》本文主要介绍了Python位移操作和位运算的实现示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一... 目录1. 位移操作1.1 左移操作 (<<)1.2 右移操作 (>>)注意事项:2. 位运算2.1

Java Spring 中 @PostConstruct 注解使用原理及常见场景

《JavaSpring中@PostConstruct注解使用原理及常见场景》在JavaSpring中,@PostConstruct注解是一个非常实用的功能,它允许开发者在Spring容器完全初... 目录一、@PostConstruct 注解概述二、@PostConstruct 注解的基本使用2.1 基本代

C语言中位操作的实际应用举例

《C语言中位操作的实际应用举例》:本文主要介绍C语言中位操作的实际应用,总结了位操作的使用场景,并指出了需要注意的问题,如可读性、平台依赖性和溢出风险,文中通过代码介绍的非常详细,需要的朋友可以参... 目录1. 嵌入式系统与硬件寄存器操作2. 网络协议解析3. 图像处理与颜色编码4. 高效处理布尔标志集合

Go语言开发实现查询IP信息的MCP服务器

《Go语言开发实现查询IP信息的MCP服务器》随着MCP的快速普及和广泛应用,MCP服务器也层出不穷,本文将详细介绍如何在Go语言中使用go-mcp库来开发一个查询IP信息的MCP... 目录前言mcp-ip-geo 服务器目录结构说明查询 IP 信息功能实现工具实现工具管理查询单个 IP 信息工具的实现服

Python ZIP文件操作技巧详解

《PythonZIP文件操作技巧详解》在数据处理和系统开发中,ZIP文件操作是开发者必须掌握的核心技能,Python标准库提供的zipfile模块以简洁的API和跨平台特性,成为处理ZIP文件的首选... 目录一、ZIP文件操作基础三板斧1.1 创建压缩包1.2 解压操作1.3 文件遍历与信息获取二、进阶技

Java中字符串转时间与时间转字符串的操作详解

《Java中字符串转时间与时间转字符串的操作详解》Java的java.time包提供了强大的日期和时间处理功能,通过DateTimeFormatter可以轻松地在日期时间对象和字符串之间进行转换,下面... 目录一、字符串转时间(一)使用预定义格式(二)自定义格式二、时间转字符串(一)使用预定义格式(二)自

SQL中redo log 刷⼊磁盘的常见方法

《SQL中redolog刷⼊磁盘的常见方法》本文主要介绍了SQL中redolog刷⼊磁盘的常见方法,将redolog刷入磁盘的方法确保了数据的持久性和一致性,下面就来具体介绍一下,感兴趣的可以了解... 目录Redo Log 刷入磁盘的方法Redo Log 刷入磁盘的过程代码示例(伪代码)在数据库系统中,r

C 语言中enum枚举的定义和使用小结

《C语言中enum枚举的定义和使用小结》在C语言里,enum(枚举)是一种用户自定义的数据类型,它能够让你创建一组具名的整数常量,下面我会从定义、使用、特性等方面详细介绍enum,感兴趣的朋友一起看... 目录1、引言2、基本定义3、定义枚举变量4、自定义枚举常量的值5、枚举与switch语句结合使用6、枚