ZetCode

Golang slices.Clone

最后修改于 2025 年 4 月 20 日

本教程将介绍如何在 Go 中使用 slices.Clone 函数。我们将通过实际示例涵盖切片克隆操作。

slices.Clone 函数创建一个新切片,该切片是原始切片的浅拷贝。它是 Go 实验性 slices 包的一部分。

当您需要切片的独立副本以防止意外修改原始数据时,此函数非常有用。它返回一个具有相同元素的新切片。

基本 slices.Clone 示例

slices.Clone 最简单的用法是创建字符串切片的副本。然后,我们可以修改副本而不影响原始切片。

basic_clone.go
package main

import (
    "fmt"
    "slices"
)

func main() {
    original := []string{"apple", "banana", "cherry"}
    clone := slices.Clone(original)
    
    clone[0] = "orange"
    
    fmt.Println("Original:", original)
    fmt.Println("Clone:", clone)
}

我们创建原始切片的克隆并更改其第一个元素。原始切片保持不变,这演示了独立副本。

克隆整数切片

slices.Clone 可用于任何切片类型。此示例克隆整数切片并修改副本。

int_clone.go
package main

import (
    "fmt"
    "slices"
)

func main() {
    nums := []int{1, 2, 3, 4, 5}
    numsCopy := slices.Clone(nums)
    
    numsCopy[0] = 100
    numsCopy = append(numsCopy, 6)
    
    fmt.Println("Original:", nums)
    fmt.Println("Clone:", numsCopy)
}

克隆开始时具有相同的元素,但可以独立修改。我们更改一个元素并附加一个新值,而不影响原始切片。

克隆结构体切片

克隆结构体切片时,请记住它是一个浅拷贝。此示例说明了结构体字段如何在原始切片和克隆之间保持共享。

struct_clone.go
package main

import (
    "fmt"
    "slices"
)

type Point struct {
    X, Y int
}

func main() {
    original := []Point{{1, 2}, {3, 4}}
    clone := slices.Clone(original)
    
    clone[0].X = 100
    
    fmt.Println("Original:", original)
    fmt.Println("Clone:", clone)
}

修改克隆中的结构体字段会影响原始切片,因为结构体是共享的。切片头不同,但指向相同的结构体值。

空切片行为

slices.Clone 可以优雅地处理空切片。此示例演示了克隆空切片并检查其属性。

empty_clone.go
package main

import (
    "fmt"
    "slices"
)

func main() {
    empty := []int{}
    clone := slices.Clone(empty)
    
    fmt.Println("Original len:", len(empty), "cap:", cap(empty))
    fmt.Println("Clone len:", len(clone), "cap:", cap(clone))
    
    clone = append(clone, 1)
    fmt.Println("Modified clone:", clone)
}

克隆是一个具有相同类型的新空切片。我们可以向其添加元素,而不会影响原始空切片,后者将保持为空。

性能注意事项

对于大型切片,克隆会产生内存和性能方面的影响。此示例对不同大小的切片进行克隆基准测试。

performance.go
package main

import (
    "fmt"
    "slices"
    "time"
)

func main() {
    sizes := []int{100, 10_000, 1_000_000}
    
    for _, size := range sizes {
        slice := make([]int, size)
        
        start := time.Now()
        _ = slices.Clone(slice)
        elapsed := time.Since(start)
        
        fmt.Printf("Size: %d, Time: %v\n", size, elapsed)
    }
}

所需时间随切片大小的增加而增加。slices.Clone 分配新内存并复制所有元素,因此请考虑大型切片的性能。

与手动复制进行比较

此示例将 slices.Clone 与使用 append 或 make+copy 进行的手动切片复制进行比较。

compare_copy.go
package main

import (
    "fmt"
    "slices"
)

func main() {
    original := []int{1, 2, 3, 4, 5}
    
    // Method 1: slices.Clone
    clone1 := slices.Clone(original)
    
    // Method 2: append
    clone2 := append([]int(nil), original...)
    
    // Method 3: make + copy
    clone3 := make([]int, len(original))
    copy(clone3, original)
    
    // Modify all clones
    clone1[0] = 100
    clone2[0] = 200
    clone3[0] = 300
    
    fmt.Println("Original:", original)
    fmt.Println("Clone1:", clone1)
    fmt.Println("Clone2:", clone2)
    fmt.Println("Clone3:", clone3)
}

所有三种方法都创建了独立副本。slices.Clone 提供了一种比手动复制技术更清晰、更易读的替代方案。

实际示例:不可变函数参数

这个实际示例展示了如何使用 slices.Clone 来保护函数参数免受修改。

immutable_params.go
package main

import (
    "fmt"
    "slices"
)

func processData(data []string) []string {
    // Create a local copy to prevent modifying input
    localCopy := slices.Clone(data)
    
    // Modify the copy
    for i := range localCopy {
        localCopy[i] = "processed_" + localCopy[i]
    }
    
    return localCopy
}

func main() {
    original := []string{"a", "b", "c"}
    result := processData(original)
    
    fmt.Println("Original:", original)
    fmt.Println("Result:", result)
}

通过克隆输入切片,我们确保原始数据保持不变。这是在使用函数中的切片参数时常见的模式。

来源

Go 实验性切片包文档

本教程通过在各种场景下创建独立切片副本的实际示例,涵盖了 Go 中的 slices.Clone 函数。

作者

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

列出所有 Go 教程