ZetCode

Golang maps.Clone

最后修改于 2025 年 4 月 20 日

本教程解释了如何在 Go 中使用 maps.Clone 函数。我们将通过创建浅拷贝的实际示例来讲解映射操作。

maps.Clone 函数创建映射的浅拷贝。它是 Go 1.18 中引入的 Go 实验性 maps 包的一部分。

当您需要使用映射的副本而不修改原始映射时,此函数非常有用。它返回一个具有相同键值对的新映射。

基本 maps.Clone 示例

maps.Clone 最简单的用法是创建字符串到整数映射的副本。对副本的更改不会影响原始映射。

basic_clone.go
package main

import (
    "fmt"
    "maps"
)

func main() {
    original := map[string]int{
        "apple":  5,
        "banana": 7,
    }
    
    copy := maps.Clone(original)
    copy["apple"] = 10
    
    fmt.Println("Original:", original)
    fmt.Println("Copy:", copy)
}

我们创建一个映射,克隆它,然后修改克隆。原始映射保持不变,这证明了克隆映射的独立性。

克隆空映射

maps.Clone 可以很好地处理空映射。此示例显示了克隆空映射并验证其行为。

empty_map.go
package main

import (
    "fmt"
    "maps"
)

func main() {
    empty := map[string]bool{}
    
    copy := maps.Clone(empty)
    copy["test"] = true
    
    fmt.Println("Original:", len(empty))
    fmt.Println("Copy:", len(copy))
}

空映射已成功克隆。向克隆中添加元素不会影响原始空映射,原始空映射将保持为空。

克隆带有结构体值的映射

克隆带有结构体值的映射时,请记住它是浅拷贝。此示例演示了带有结构体值的行为。

struct_values.go
package main

import (
    "fmt"
    "maps"
)

type Point struct {
    X, Y int
}

func main() {
    original := map[string]Point{
        "center": {0, 0},
    }
    
    copy := maps.Clone(original)
    point := copy["center"]
    point.X = 100
    
    fmt.Println("Original:", original)
    fmt.Println("Copy:", copy)
}

修改结构体值需要重新赋值。克隆包含结构体值的副本,但它们是与原始实例分开的。

克隆 nil 映射

maps.Clone 可以安全地处理 nil 映射。此示例显示了克隆 nil 映射时的行为。

nil_map.go
package main

import (
    "fmt"
    "maps"
)

func main() {
    var nilMap map[int]string
    
    copy := maps.Clone(nilMap)
    
    fmt.Println("Original is nil:", nilMap == nil)
    fmt.Println("Copy is nil:", copy == nil)
}

克隆 nil 映射会返回另一个 nil 映射。这种行为与 Go 在其他上下文中处理 nil 集合的方式一致。

性能注意事项

对于大型映射,克隆可能会很昂贵。此示例对大型映射的克隆操作进行基准测试。

performance.go
package main

import (
    "fmt"
    "maps"
    "time"
)

func main() {
    largeMap := make(map[int]int, 1_000_000)
    for i := 0; i < 1_000_000; i++ {
        largeMap[i] = i * 2
    }
    
    start := time.Now()
    _ = maps.Clone(largeMap)
    elapsed := time.Since(start)
    
    fmt.Printf("Cloned 1,000,000 elements in %v\n", elapsed)
}

基准测试显示了克隆大型映射所需的时间。内存分配是映射克隆操作的主要成本因素。

实际示例:配置复制

这个实际示例演示了在为特定用例进行修改之前克隆配置映射。

config_copy.go
package main

import (
    "fmt"
    "maps"
)

func main() {
    defaultConfig := map[string]interface{}{
        "timeout":  30,
        "retries":  3,
        "logging":  true,
    }
    
    testConfig := maps.Clone(defaultConfig)
    testConfig["timeout"] = 5
    testConfig["logging"] = false
    
    fmt.Println("Default config:", defaultConfig)
    fmt.Println("Test config:", testConfig)
}

我们在修改设置进行测试之前克隆默认配置。原始配置保持不变,可供其他用途使用。

将 Clone 与手动复制进行比较

此示例将 maps.Clone 与手动映射复制进行比较,以证明它们的等效性。

manual_copy.go
package main

import (
    "fmt"
    "maps"
)

func main() {
    original := map[rune]string{
        'A': "Apple",
        'B': "Banana",
    }
    
    clone1 := maps.Clone(original)
    clone2 := make(map[rune]string, len(original))
    
    for k, v := range original {
        clone2[k] = v
    }
    
    fmt.Println("maps.Clone result:", clone1)
    fmt.Println("Manual copy result:", clone2)
}

两种方法都产生等效的结果,但 maps.Clone 更简洁,并且可以自动处理 nil 映射等边缘情况。

来源

Go 实验性 maps 包文档

本教程通过在各种场景下创建映射浅拷贝的实际示例,介绍了 Go 中的 maps.Clone 函数。

作者

我叫 Jan Bodnar,我是一名充满热情的程序员,拥有丰富的编程经验。我自 2007 年以来一直撰写编程文章。迄今为止,我已撰写了 1,400 多篇文章和 8 本电子书。我在教授编程方面拥有十多年的经验。

列出所有 Go 教程