Skip to content

如何在 Go 语言中合并两个 map

Posted on:2024年6月9日 at 21:59

在 Go 语言编程中,我们常常需要处理键值对集合,即 map。特别是在递归处理文件路径时,可能需要将多个 map 合并成一个。这个操作相当于集合的并集操作:将一个 map 中的键值对更新到另一个 map 中。本文将介绍如何在 Go 中合并两个 map。

使用 Go 1.21 及更高版本的 maps.Copy 函数

自 Go 1.21 起,Go 语言提供了一个新的标准库函数 maps.Copy,可以方便地将一个 map 的所有键值对复制到另一个 map 中。

示例代码

package main

import (
    "fmt"
    "maps"
)

func main() {
    src := map[string]int{
        "one": 1,
        "two": 2,
    }
    dst := map[string]int{
        "two":   42,
        "three": 3,
    }
    maps.Copy(dst, src)
    fmt.Println("src:", src)
    fmt.Println("dst:", dst)
}

输出结果

src: map[one:1 two:2]
dst: map[one:1 three:3 two:2]

在上面的例子中,我们定义了两个 map srcdst,并使用 maps.Copy 函数将 src 中的键值对复制到 dst 中。最终,dst 包含了两个 map 的所有键值对,其中 src 中的键值对覆盖了 dst 中相同键的值。

使用 Go 1.18 到 Go 1.20 的 golang.org/x/exp/maps.Copy 函数

在 Go 1.18 到 Go 1.20 版本中,可以使用 golang.org/x/exp/maps 包中的 Copy 函数来实现相同的功能。

示例代码

package main

import (
    "fmt"
    "golang.org/x/exp/maps"
)

func main() {
    src := map[string]int{
        "one": 1,
        "two": 2,
    }
    dst := map[string]int{
        "two":   42,
        "three": 3,
    }
    maps.Copy(dst, src)
    fmt.Println("src:", src)
    fmt.Println("dst:", dst)
}

输出结果

src: map[one:1 two:2]
dst: map[one:1 three:3 two:2]

需要注意的是,在 Go 1.18.x 到 1.19.x 版本中,Copy 函数要求 map 的键类型必须是具体类型,而不是接口类型。如果键类型是接口类型,编译器将无法通过编译。

!!!错误示例!!!

package main

import (
    "fmt"
    "io"
    "golang.org/x/exp/maps"
)

func main() {
    var src, dst map[io.Reader]int
    maps.Copy(dst, src)
    fmt.Println("src:", src)
    fmt.Println("dst:", dst)
}

编译错误

./prog.go:12:11: io.Reader does not implement comparable

在 Go 1.20 及更高版本中,这一限制已被移除。

手动合并 map

在不使用上述新功能的情况下,我们也可以手动迭代一个 map,并将其键值对添加到另一个 map 中。

示例代码

package main

import (
    "fmt"
)

func mergeMaps(dst, src map[string]int) {
    for key, value := range src {
        dst[key] = value
    }
}

func main() {
    src := map[string]int{
        "one": 1,
        "two": 2,
    }
    dst := map[string]int{
        "two":   42,
        "three": 3,
    }
    mergeMaps(dst, src)
    fmt.Println("src:", src)
    fmt.Println("dst:", dst)
}

输出结果

src: map[one:1 two:2]
dst: map[one:1 three:3 two:2]