在大多数语言(如 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 完全陌生,并试图很好地理解基础知识。
解释相当简单:在上面的代码中没有显式声明或使用单个数组。您的 tab
局部变量和
tab
参数是slices。 在 Go 中,数组的长度是类型的一部分,例如
[3]int
(这在某种程度上是正确的,例如
[2]int
和
[3]int
是两种不同/不同的数组类型)。如果长度不存在(要么像
[2]int
那样显式,要么像复合文字
[...]int{1, 2, 3}
那样隐式),那么这不是数组类型,而是切片类型。是的,正如您所读到的,数组值意味着它的所有元素,并且当传递(或分配)时,它的所有元素都会被复制。然而,切片只是小的描述符、标头,描述数组的连续部分;当切片被传递(或分配)时,仅复制此标头(包括指针),它将指向相同的底层数组。因此,如果您修改切片副本的元素,则更改将反映在原始切片中,因为只有一个支持数组保存这些元素。
如果你想确切地知道切片头中的内容,可以查看reflect.SliceHeader
struct
,包含指向切片第一个元素的指针、切片的长度和容量.
请阅读以下博客文章,其中详细解释了这一点:
另请参阅这些相关问题以了解更多详细信息: