Skip to main content

Std map

Go 1.21 引入了一些新的标准库函数来操作 map 类型的数据结构。这些函数提供了更便捷和通用的方式来处理映射。以下是这些函数的详细说明:

Clone

func Clone[M ~map[K]V, K comparable, V any](m M) M

Clone 函数创建并返回一个给定映射 m 的副本。这个副本是一个新的映射,包含了原映射中的所有键值对。

示例:

original := map[string]int{"a": 1, "b": 2}
copy := Clone(original)

Copy

func Copy[M1 ~map[K]V, M2 ~map[K]V, K comparable, V any](dst M1, src M2)

Copy 函数将 src 映射中的所有键值对复制到 dst 映射中。如果 dst 中已经存在某个键,则其值将被覆盖。

示例:

src := map[string]int{"a": 1, "b": 2}
dst := map[string]int{"b": 3, "c": 4}
Copy(dst, src)
// dst 现在是 map[string]int{"a": 1, "b": 2, "c": 4}

DeleteFunc

func DeleteFunc[M ~map[K]V, K comparable, V any](m M, del func(K, V) bool)

DeleteFunc 函数根据给定的条件函数 del 删除映射 m 中的键值对。del 函数接受键和值作为参数,并返回一个布尔值,指示是否应删除该键值对。

示例:

m := map[string]int{"a": 1, "b": 2, "c": 3}
DeleteFunc(m, func(k string, v int) bool {
return v%2 == 0 // 删除所有值为偶数的键值对
})
// m 现在是 map[string]int{"a": 1, "c": 3}

Equal

func Equal[M1, M2 ~map[K]V, K, V comparable](m1 M1, m2 M2) bool

Equal 函数比较两个映射 m1m2 是否相等。如果两个映射具有相同的键值对,则它们被认为是相等的。

示例:

m1 := map[string]int{"a": 1, "b": 2}
m2 := map[string]int{"a": 1, "b": 2}
equal := Equal(m1, m2) // equal 是 true

EqualFunc

func EqualFunc[M1 ~map[K]V1, M2 ~map[K]V2, K comparable, V1, V2 any](m1 M1, m2 M2, eq func(V1, V2) bool) bool

EqualFunc 函数比较两个映射 m1m2 是否相等,但使用自定义的比较函数 eq 来比较值。eq 函数接受两个值作为参数,并返回一个布尔值,指示它们是否相等。

示例:

m1 := map[string]int{"a": 1, "b": 2}
m2 := map[string]float64{"a": 1.0, "b": 2.0}
equal := EqualFunc(m1, m2, func(v1 int, v2 float64) bool {
return float64(v1) == v2
}) // equal 是 true

这些新引入的函数使得处理映射更加方便和灵活,特别是在需要进行复杂操作或比较时。

这些 api 看起来很鸡肋

虽然这些新引入的 map 操作函数可能在某些情况下看起来不太必要,但它们实际上提供了一些有用的功能,使得代码更简洁和易读。以下是一些具体场景,说明这些函数的实用性:

1. Clone

场景: 当你需要对一个映射进行修改,但又不想改变原始映射时,Clone 函数非常有用。

示例:

original := map[string]int{"a": 1, "b": 2}
copy := Clone(original)
copy["a"] = 10
// original 仍然是 {"a": 1, "b": 2}
// copy 是 {"a": 10, "b": 2}

2. Copy

场景: 当你需要合并两个映射时,Copy 函数可以简化代码。

示例:

src := map[string]int{"a": 1, "b": 2}
dst := map[string]int{"b": 3, "c": 4}
Copy(dst, src)
// dst 现在是 {"a": 1, "b": 2, "c": 4}

3. DeleteFunc

场景: 当你需要根据复杂条件删除映射中的键值对时,DeleteFunc 提供了更灵活的解决方案。

示例:

m := map[string]int{"a": 1, "b": 2, "c": 3}
DeleteFunc(m, func(k string, v int) bool {
return v%2 == 0 // 删除所有值为偶数的键值对
})
// m 现在是 {"a": 1, "c": 3}

4. Equal

场景: 当你需要比较两个映射是否相等时,Equal 函数提供了一种更简洁的方式,而不需要手动遍历映射。

示例:

m1 := map[string]int{"a": 1, "b": 2}
m2 := map[string]int{"a": 1, "b": 2}
equal := Equal(m1, m2) // equal 是 true

5. EqualFunc

场景: 当你需要使用自定义规则比较两个映射时,EqualFunc 提供了灵活性。

示例:

m1 := map[string]int{"a": 1, "b": 2}
m2 := map[string]float64{"a": 1.0, "b": 2.0}
equal := EqualFunc(m1, m2, func(v1 int, v2 float64) bool {
return float64(v1) == v2
}) // equal 是 true

总结

这些函数的引入并不是为了替代现有的手动操作,而是为了提供更简洁、可读性更强的代码。对于一些常见的操作,如克隆、复制、删除和比较映射,这些函数可以显著简化代码并减少错误的可能性。虽然在某些简单场景下它们看起来可能有些多余,但在复杂操作和条件下,它们的优势会更明显。

Equal 是浅比较

在 Go 1.21 中引入的 Equal 函数用于比较两个 map 是否相等,它进行的是浅比较,而不是深比较。这意味着 Equal 仅比较两个 map 的键和值,而不递归地比较值中的嵌套结构。

Equal 函数的定义

func Equal[M1, M2 ~map[K]V, K, V comparable](m1 M1, m2 M2) bool

解释

  • 浅比较Equal 函数只会比较两个 map 中的键和值是否相等。对于值类型是嵌套结构的情况(例如 map、slice、struct 等),它只会比较这些值的顶层引用或值,而不会递归地比较嵌套的内容。

示例

m1 := map[string]int{"a": 1, "b": 2}
m2 := map[string]int{"a": 1, "b": 2}
equal := Equal(m1, m2) // equal 是 true

在这个示例中,Equal 函数会返回 true,因为 m1m2 有相同的键和值。

嵌套结构的情况

如果 map 的值是嵌套结构,例如另一个 map 或 slice,Equal 函数只会比较这些值的引用或顶层值,而不会递归比较其内容。

m1 := map[string][]int{"a": {1, 2}, "b": {3, 4}}
m2 := map[string][]int{"a": {1, 2}, "b": {3, 4}}
equal := Equal(m1, m2) // equal 是 false

在这个示例中,Equal 函数会返回 false,因为 m1m2 中的 slice 是不同的引用,即使它们的内容相同。

深比较

如果需要对嵌套结构进行深比较,可以使用 EqualFunc 函数并提供自定义的比较函数,或者使用其他库(如 reflect.DeepEqual)。

使用 EqualFunc 进行深比较

m1 := map[string][]int{"a": {1, 2}, "b": {3, 4}}
m2 := map[string][]int{"a": {1, 2}, "b": {3, 4}}
equal := EqualFunc(m1, m2, func(v1, v2 []int) bool {
if len(v1) != len(v2) {
return false
}
for i := range v1 {
if v1[i] != v2[i] {
return false
}
}
return true
})
// equal 是 true

在这个示例中,我们使用 EqualFunc 并提供了一个自定义的比较函数来进行深比较。

总结

Equal 函数进行的是浅比较,仅比较两个 map 的键和值。如果需要深比较,可以使用 EqualFunc 并提供自定义的比较函数,或者使用其他库如 reflect.DeepEqual