Go语言中切片(slice)和字典(map)扩展方法

前言

Go本身slice的方法是较少的,其他语言中的过滤和转换相关的经常使用的方法也没有,我们可以扩展一下方便使用。

切片slice

过滤

方法

通过一个函数参数来过滤所需的元素,只有满足条件元素才返回到结果集中:

1
2
3
4
5
6
7
8
9
10
func SliceFilter[T any](s []T, fn func(T) bool) []T {
result := make([]T, 0, len(s))
for _, v := range s {
if fn(v) {
result = append(result, v)
}
}

return result
}

判空也是常用的功能,获取所有非空集:

1
2
3
4
5
func SliceFilterNonNil[T any](s []*T) []*T {
return SliceFilter(s, func(t *T) bool {
return t != nil
})
}

调用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package test

import (
"fmt"
"strings"
"testing"
"xh-control-ws/utils"
)

// 普通的测试
func Test02(t *testing.T) {
var nameList []string
nameList = append(nameList, "张三", "李四", "王五")
result := utils.SliceFilter(nameList, func(item string) bool {
return strings.HasPrefix(item, "张")
})
fmt.Println(result) // 输出过滤后的结果
}

转换

方法

通过一个转换函数,可方便地把原切片转换为新的切片:

1
2
3
4
5
6
7
func SliceTrans[S, R any](s []S, fn func(S) R) []R {
result := make([]R, 0, len(s))
for _, v := range s {
result = append(result, fn(v))
}
return result
}

若只需要转换满足条件的元素,可先过滤再转换:

1
2
3
4
5
6
7
8
9
10
func SliceTransWithFilter[S, R any](s []S, fn func(S) (R, bool)) []R {
result := make([]R, 0, len(s))
for _, v := range s {
if r, ok := fn(v); ok {
result = append(result, r)
}

}
return result
}

调用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package test

import (
"fmt"
"testing"
"xh-control-ws/utils"
)

// 普通的测试
func Test02(t *testing.T) {
var nameList []string
nameList = append(nameList, "张三", "李四", "王五")
result := utils.SliceTrans(nameList, func(item string) string {
return item + "同学"
})
fmt.Println(result)
}

累计

对切片中的元素累计,获取一个最终结果:

1
2
3
4
5
6
7
8
func SliceAccum[S, R any](init R, s []S, fn func(last R, ele S) R) R {
result := init
for _, v := range s {
result = fn(result, v)
}

return result
}

字典 map

创建Map

1
var schoolUserMap = map[string]string{}

过滤

方法

1
2
3
4
5
6
7
8
9
10
func MapFilter[K comparable, V any](m map[K]V, fn func(key K, value V) bool) map[K]V {
result := make(map[K]V, len(m))
for k, v := range m {
if fn(k, v) {
result[k] = v
}
}

return result
}

调用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package test

import (
"fmt"
"testing"
"xh-control-ws/utils"
)

// 普通的测试
func Test01(t *testing.T) {
userinfo := map[string]string{"name": "xiaoming"}
userinfo["name"] = "xiaohong"
userinfo["age"] = "18"

result := utils.MapFilter(userinfo, func(key string, value string) bool {
return key == "name"
})
fmt.Println(result)
}

结果

1
map[name:xiaohong]

转换

方法

1
2
3
4
5
6
7
8
9
func MapTrans[K comparable, V, R any](m map[K]V, fn func(key K, value V) (R, bool)) map[K]R {
result := make(map[K]R, len(m))
for k, v := range m {
if r, ok := fn(k, v); ok {
result[k] = r
}
}
return result
}

调用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package test

import (
"fmt"
"strings"
"testing"
"xh-control-ws/utils"
)

// 普通的测试
func Test01(t *testing.T) {
userinfo := map[string]string{"name": "xiaoming"}
userinfo["name"] = "xiaohong"
userinfo["age"] = "18"

result := utils.MapTrans(userinfo, func(key string, value string) (string, bool) {
if key == "name" {
return strings.ToUpper(value), true
} else {
return value + "岁", true
}
})
fmt.Println(result)
}

结果

1
map[age:18岁 name:XIAOHONG]

其中返回值中的bool,代表对应的key是否保留。