Go中的数组处理

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

Treatment of Arrays in Go

问题

阅读了http://golang.org/doc/effective_go.html#arrays中的以下内容后...

> * 数组是值。将一个数组赋值给另一个数组会复制所有元素。
> * 特别地,如果将一个数组传递给函数,函数会接收到该数组的一个副本,而不是指向它的指针。

... 我期望在以下代码中arr2arr是不同的,main()中的arrshuffle()中的arr也是不同的。有人能解释一下为什么以下代码会对arr2进行洗牌吗?我知道Go语言还很年轻,也许对数组的处理方式已经改变了?

package main

import (
        "fmt"
        "rand"
        "time"
)

func shuffle(arr []int) {
        rand.Seed(time.Nanoseconds())
        for i := len(arr) - 1; i > 0; i-- {
                j := rand.Intn(i)
                arr[i], arr[j] = arr[j], arr[i]
        }
}

func main() {
        arr := []int{1, 2, 3, 4, 5}
        arr2 := arr
        shuffle(arr)
        for _, i := range arr2 {
                fmt.Printf("%d ", i)
        }
}
英文:

Having read the following at http://golang.org/doc/effective_go.html#arrays...

> * Arrays are values. Assigning one array to another copies all the
> elements.
> * In particular, if you pass an array to a function, it will receive a copy
> of the array, not a pointer to it.

... I expect in the following code that arr2 to be distinct from arr, and main()'s arr to be distinct from shuffle()'s arr. Can someone please explain why the following code shuffles arr2? I know Go is still a young language; perhaps the treatment of arrays has changed?

package main

import (
        "fmt"
        "rand"
        "time"
)

func shuffle(arr []int) {
        rand.Seed(time.Nanoseconds())
        for i := len(arr) - 1; i > 0; i-- {
                j := rand.Intn(i)
                arr[i], arr[j] = arr[j], arr[i]
        }
}

func main() {
        arr := []int{1, 2, 3, 4, 5}
        arr2 := arr
        shuffle(arr)
        for _, i := range arr2 {
                fmt.Printf("%d ", i)
        }
}

答案1

得分: 21

我认为你的问题是你混淆了数组和切片。

数组是固定长度的值列表。在你的示例中实际上没有使用任何数组。数组可以通过几种方式声明:

arr1 := [3]int{1, 2, 3}   // 一个包含3个整数(1-3)的数组
arr2 := [...]int{1, 2, 3} // 与上一行相同,但我们让编译器来确定数组的大小
var arr3 [3]int           // 一个包含3个整数的零值数组

你正在使用切片。切片是对底层数组的引用。有几种分配新切片的方式:

slice1 := []int{1, 2, 3}    // 一个包含整数1-3的长度为3的切片
slice2 := make([]int, 3)    // 一个包含三个零值整数的长度为3的切片
slice3 := make([]int, 3, 5) // 一个长度为3、容量为5的全零切片

任何其他的切片赋值只是复制对数组的引用。

现在我们已经确定了这一点,这行代码

arr := []int{1, 2, 3, 4, 5}

创建了一个引用匿名底层数组的切片,该数组包含数字1-5。

arr2 := arr

复制了该引用,而不是复制底层数组。因此,有一个底层数组和两个对它的引用。这就是为什么当你修改arr的内容时,arr2的内容也会改变。它们引用的是同一个数组。

英文:

I think your problem is that you're confusing arrays and slices.

Arrays are fixed-length lists of values. You're actually not using any arrays in your example. Arrays can be declared a few ways:

arr1 := [3]int{1, 2, 3}   // an array of 3 integers, 1-3
arr2 := [...]int{1, 2, 3} // same as the previous line, but we're letting
                          // the compiler figure out the size of the array
var arr3 [3]int           // a zeroed out array of 3 integers

You're using slices. A slice is a reference to an underlying array. There are a few ways to allocate new slices:

slice1 := []int{1, 2, 3}    // a slice of length 3 containing the integers 1-3
slice2 := make([]int, 3)    // a slice of length 3 containing three zero-value integers
slice3 := make([]int, 3, 5) // a slice of length 3, capacity 5 that's all zeroed out

Any other slice assignments are just duplicating a reference to an array.

Now that we've established that, the line

arr := []int{1, 2, 3, 4, 5}

creates a slice referencing an anonymous underlying array that contains the numbers 1-5.

arr2 := arr

duplicates that reference -- it does not copy the underlying array. So there's one underlying array and two references to it. That's why the contents of arr2 change when you modify the contents of arr. They're referencing the same array.

huangapple
  • 本文由 发表于 2010年11月19日 10:52:13
  • 转载请务必保留本文链接:https://go.coder-hub.com/4221698.html
匿名

发表评论

匿名网友

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

确定