【问题标题】:How to pass a copy of a slice to a function?如何将切片的副本传递给函数?
【发布时间】:2017-09-18 16:39:52
【问题描述】:

我对将切片传递给函数有疑问。

如果我没记错的话,切片是在 Go 中通过引用传递的,所以如果我这样做:

package main

import "fmt"

func main() {
    slice := []int{1, 2, 3, 4, 5}
    fmt.Println(slice)
    testSlice(slice)
    fmt.Println(slice)
}

func testSlice(slice []int) {
    slice[0] = 5
    slice[4] = 1
}

testSlice 函数实际上会更改原始切片中的值,因为它是通过引用传递的(默认情况下)。

有一些简单的方法可以直接将切片的副本传递给testSlice 函数吗?

当然我可以这样做来创建切片的副本:

package main

import "fmt"

func main() {
    slice := []int{1, 2, 3, 4, 5}
    fmt.Println(slice)
    testSlice(slice)
    fmt.Println(slice)
}

func testSlice(slice []int) {
    var newSlice []int
    for i := 0; i < len(slice); i++ {
        newSlice = append(newSlice, slice[i])
    }
    newSlice[0] = 5
    newSlice[4] = 1
}

但是它需要遍历原始切片中的所有值来复制它们,并且这似乎不是一个很好的解决方案。

【问题讨论】:

    标签: go slice


    【解决方案1】:

    有一个内置函数copyfunc copy(dst, src []T) int,这可能就是您要找的。它将任意类型的切片复制到另一个切片中。

    来自docs

    复制功能支持在不同长度的切片之间复制(它只会复制到较少数量的元素)。此外,copy 可以处理共享相同底层数组的源切片和目标切片,正确处理重叠切片。

    所以

    list := []string{"hello", "world"}
    newList := make([]string, len(list))
    n := copy(newList, list)
    // n is the number of values copied
    

    list 复制到一个新的切片newList,它共享值但不共享内存中的引用。 int copy 返回的是复制的值的数量。


    对于另一种方法,从 Kostix 的评论中,您可以将切片附加到空切片。这有点像复制它。这可能不是惯用的,但它允许您将切片作为副本传递到func有点。如果你这样做,我推荐大量的 cmets。

    thisFuncTakesSliceCopy( append([]string(nil), list...) )
    

    要将切片附加到另一个切片,请记住省略号 (...)。

    【讨论】:

    • 感谢@Nevermore,这是一种更优雅的复制slice 的方式。只想确认一下。我无法将slice 副本直接传递给函数吗?唯一的方法是手动创建一个新的slice 并从原始slice 复制值?我只是问它,因为我来自C++,在那里我可以通过引用或值传递向量。
    • @KelvinSalton go 绝对没有“通过引用传递”的概念。一切都是按值传递的。切片是底层数组的描述符。如果你想要数组的那部分的副本,你必须制作一个副本。 Go 的重点不是“优雅”或“语法糖”而是“显式”:
    • 也可以使用b := append([]byte(nil), a...) 将整个a 附加到一个零切片——本质上是生成一个分配给b 的副本。
    猜你喜欢
    • 2018-06-15
    • 1970-01-01
    • 1970-01-01
    • 2017-02-10
    • 1970-01-01
    • 2012-11-22
    • 1970-01-01
    • 2017-01-12
    • 2018-04-22
    相关资源
    最近更新 更多