Golang将数组传递给函数并对其进行修改

huangapple go评论93阅读模式
英文:

Golang passing arrays to the function and modifying it

问题

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

这让我有点困惑-这难道不意味着不使用引用传递数组就不会修改数组本身吗?让我举个例子:

func main() {
    tab := []int{1, 2, 3}
    fmt.Println(tab)
    // 输出 [1 2 3]
    reverse(tab)
    fmt.Println(tab)
    // 输出 [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]
    }
}

在上面的代码中,数组并没有通过引用传递,但是reverse函数修改了原始数组,所以它的行为有点像C++程序。有人可以解释一下这种差异吗?

PS:如果这是一个愚蠢的问题,对不起,我对Golang完全是新手,正在努力理解基础知识。

英文:

In most languages (like c++) passing arrays result in implicitly passing it by a reference, so any changes to the passed array in the function will result in changing the original one. I am learning Golang, and In the book "The Go Programming Language" by Alan A.A. Donovan and Brian W. Kernighan It is said, that its behaviour is different from other languages - It does not implicitly pass array by reference.

It is confusing me a bit - doesn't that mean that passing an array without the reference should not modify the array itself? Let me illustrate that:

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 &lt; j; i, j = i+1, j-1 {
		tab[i], tab[j] = tab[j], tab[i]
	}
}

In code above array is not passed by the reference, but the reverse function modifies the original one, so It works somewhat like C++ program would do. Could anyone explain me the difference?

PS: Sorry if it is a dummy question, I am totally new to the Golang and trying to understand the basics well.

答案1

得分: 13

解释相当简单:在你上面的代码中,没有声明或明确使用任何单个数组。你的tab局部变量和tab参数都是切片。

在Go语言中,数组的长度是类型的一部分,例如[3]int(这是真实的,例如[2]int[3]int是两种不同的数组类型)。如果长度不存在(无论是显式的,如[2]int,还是隐式的,如复合字面量[...]int{1, 2, 3}),那么它不是数组类型,而是切片类型。

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

如果你想知道切片头部的具体内容,你可以查看reflect.SliceHeader类型:它是一个包含切片第一个元素的指针、切片的长度和容量的结构体。

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

Go切片:用法和内部机制

数组、切片(和字符串):'append'的机制

还可以参考以下相关问题以获取更多细节:

https://stackoverflow.com/questions/38645175/why-have-arrays-in-go

https://stackoverflow.com/questions/39993688/are-golang-slices-pass-by-value

英文:

The explanation is rather simple: there isn't a single array declared or used explicitly in your code above. Your tab local variable and the tab parameter are slices.

In Go the length of an array is part of the type, e.g. [3]int (this is true to an extent that for example [2]int and [3]int are 2 different / distinct array types). If the length is not present (either explicit like [2]int or implicit like in the composite literal [...]int{1, 2, 3}), then that is not an array type but a slice type.

Yes, as you read, an array value means all its elements, and when passed around (or assigned), all its elements are copied. Slices however are just small descriptors, headers, describing a contiguous section of an array; and when slices are passed around (or assigned), only this header is copied (the pointer included), which will point to the same underlying array. And so if you modify the elements of the slice-copy, the changes will be reflected in the original slice as there is only one backing array that holds the elements.

<sup>If you want to know what's in a slice header exactly, you may check out the reflect.SliceHeader type: it's a struct containing the pointer to the first element of the slice, the length and the capacity of the slice.</sup>

Please read the following blog posts which explain this in great details:

Go Slices: usage and internals

Arrays, slices (and strings): The mechanics of 'append'

Also see these related questions for more details:

https://stackoverflow.com/questions/38645175/why-have-arrays-in-go

https://stackoverflow.com/questions/39993688/are-golang-slices-pass-by-value

答案2

得分: 1

你所定义的不是array,而是一个按引用传递的arrayslice,这在golang文档中有明确说明。请查看此链接

英文:

What you are defining is not array but a slice of an array which is passed by reference as specified in golang documentation. Check this link.

huangapple
  • 本文由 发表于 2016年11月10日 03:27:51
  • 转载请务必保留本文链接:https://go.coder-hub.com/40514555.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定