当前位置: 代码网 > it编程>前端脚本>Golang > Go语言利用泛型封装常见的Map操作

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

2025年02月13日 Golang 我要评论
什么是泛型泛型是一种编程范式,允许开发者在编写代码时定义通用的类型参数,而不是具体的类型。通过泛型,可以编写出能够处理多种数据类型的代码,而无需为每种类型重复编写相同的逻辑。例如,一个泛型函数可以同时

什么是泛型

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

泛型解决了什么问题

在 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] = v
       }
       return true
    })
    return m
}

10.map转sync.map

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.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 := 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
    })
    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 {
       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操作的资料请关注代码网其它相关文章!

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com