在大多数语言(如c ++)中,传递数组会导致通过引用隐式传递它,因此对函数中传递的数组的任何更改都将导致更改原始数组。我正在学习Golang,并在Alan A.A.的“The Go Programming Language”一书中学习。 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完全不熟悉,并试图更好地理解基础知识。
答案 0 :(得分:4)
解释相当简单:上面的代码中没有明确声明或使用的array。您的tab
本地变量和tab
参数为slices。
在Go中,数组的长度是类型的一部分,例如[3]int
(例如,[2]int
和[3]int
是2种不同/不同的数组类型,这是正确的。如果长度不存在(显式为[2]int
或隐式,如composite literal [...]int{1, 2, 3}
),那么这不是数组类型而是切片类型。
是的,正如您所读到的,数组值表示其所有元素,并且在传递(或分配)时,将复制其所有元素。然而,切片只是小描述符,标题,描述数组的连续部分;当传递切片(或分配)时,只复制此标头(包括指针),这将指向相同的底层数组。因此,如果修改切片副本的元素,更改将反映在原始切片中,因为只有一个支持数组的支持数组。
如果你想知道切片头中的确切内容,你可以查看reflect.SliceHeader
类型:它是一个struct
,包含指向切片第一个元素的指针,长度以及切片的容量。
请阅读以下博客文章,详细解释了这一点:
Go Slices: usage and internals
Arrays, slices (and strings): The mechanics of 'append'
有关详情,请参阅以下相关问题:
答案 1 :(得分:1)
您定义的内容不是array
,而是数组的slice
,该数组按照golang文档中的指定通过引用传递。查看this链接。