Golang 将数组传递给函数并修改它

问题描述 投票:0回答:3

在大多数语言(如 c++)中,传递数组会导致通过引用隐式传递数组,因此对函数中传递的数组的任何更改都将导致原始数组的更改。我正在学习 Golang,在 Alan A.A. 的《Go 编程语言》一书中Donovan 和 Brian W. Kernighan 据说,它的行为与其他语言不同 - 它不会通过引用隐式传递数组。

这让我有点困惑 - 这是否意味着在没有引用的情况下传递数组不应修改数组本身?让我来说明一下:

func main() {
    tab := []int{1, 2, 3}
    fmt.Println(tab)
    // Results in [1 2 3]
    reverse(tab)
    fmt.Println(tab)
    // Results in [3 2 1]
}

func reverse(tab []int) {
    for i, j := 0, len(tab)-1; i < j; i, j = i+1, j-1 {
        tab[i], tab[j] = tab[j], tab[i]
    }
}

在上面的代码中,数组不是通过引用传递的,而是反向函数修改了原始数组,所以它的工作方式有点像C++程序。谁能给我解释一下其中的区别吗?

PS:抱歉,如果这是一个虚拟问题,我对 Golang 完全陌生,并试图很好地理解基础知识。

c++ arrays go reference
3个回答
13
投票

解释相当简单:在上面的代码中没有显式声明或使用单个数组。您的 tab

 局部变量和 
tab
 参数是 
slices

在 Go 中,数组的长度是类型的一部分,例如

[3]int

(这在某种程度上是正确的,例如 
[2]int
[3]int
 是两种不同/不同的数组类型)。如果长度不存在(要么像 
[2]int
 那样显式,要么像 
复合文字 [...]int{1, 2, 3}
 那样隐式),那么这不是数组类型,而是切片类型。

是的,正如您所读到的,数组值意味着它的所有元素,并且当传递(或分配)时,它的所有元素都会被复制。然而,切片只是小的描述符、标头,描述数组的连续部分;当切片被传递(或分配)时,仅复制此标头(包括指针),它将指向相同的底层数组。因此,如果您修改切片副本的元素,则更改将反映在原始切片中,因为只有一个支持数组保存这些元素。

如果你想确切地知道切片头中的内容,可以查看reflect.SliceHeader

类型:它是一个struct
,包含指向切片第一个元素的指针、切片的长度和容量.

请阅读以下博客文章,其中详细解释了这一点:

Go Slices:用法和内部结构

数组、切片(和字符串):“追加”的机制

另请参阅这些相关问题以了解更多详细信息:

Go 中为什么有数组?

golang 切片是按值传递的吗?


1
投票
您定义的不是

array

 ,而是一个数组的 
slice
 ,该数组是按照 golang 文档中指定的引用传递的。检查
这个链接。


0
投票
我发现这里点赞最多的回复可能有错误。 根据

https://go.dev/blog/slices-intro

[...]int{1, 2, 3}

 不是一个切片,而是一个包含 3 个元素的固定数组。
换句话说:这是 
[2]int
 不是 
[]int

    

© www.soinside.com 2019 - 2024. All rights reserved.