Golang数组使用中的常见问题与解决方案

Golang数组使用中的常见问题与解决方案 // 为什么打印出的 ‘array’ 所有槽位都只填充了最后追加的条目?

package main
import  “fmt”
var array [][]int
var pos []int
func main() {
pos = append(pos, 0)
pos = append(pos, 0)
array = make([][]int, 0, 100)
count := 0
for i := 0; i < 2; i++ {
for j := 0; j < 2; j++ {
pos[0] = j
pos[1] = 0
fmt.Println(“i=”, i, “j=”, j, “count=”, count, “pos=”, pos)
array = append(array, pos)
fmt.Println(“appending pos=”, pos, “to array”)
fmt.Println(“just added”, array[count])
count++
}
}
fmt.Println(“size is”, len(array))
fmt.Println(“array”, array)
}
// 谢谢!

更多关于Golang数组使用中的常见问题与解决方案的实战教程也可以访问 https://www.itying.com/category-94-b0.html

3 回复

因为切片本身就是一个指针,所以实际上你是在操作 pos 中的同一个指针。

			// array = append(array, pos)
			array = append(array, []int{pos[0], pos[1]})
			// or
			array = append(array, append(make([]int, 0, len(pos)), pos...))
			// or other...

更多关于Golang数组使用中的常见问题与解决方案的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


切片是一个引用,因此当你创建切片 pos 并添加两个元素时,它只被创建一次,当你分配新值时,你实际上是分配到了同一个地址。

var pos []int			// 这里 pos 是 nil
pos = append(pos, 0)
pos = append(pos, 0)

因此,你需要在循环内部创建 pos 切片。

for j := 0; j < 2; j++ {
  	pos := make([]int, 2)
  	pos[0] = j
  	pos[1] = 0
  	fmt.Printf("address of pos %p \n", &pos)
  	fmt.Println("i=", i, "j=", j, "count=", count, "pos=", pos)
		array = append(array, pos)
		fmt.Println("appending pos=", pos, "to array")
		fmt.Println("just added", array[count])

		count++
	}

要检查你切片的地址,只需

fmt.Printf("address of pos %p \n", &pos)

这是一个典型的切片引用问题。pos 切片在内存中只有一个底层数组,每次修改 pos[0]pos[1] 都是在修改同一个底层数组。当执行 array = append(array, pos) 时,实际上是将 pos 切片的引用(指针)追加到 array 中,而不是复制其当前值。

因此,array 中所有元素都指向同一个 pos 切片,最终所有槽位都显示 pos 最后被修改的值 [1 0]

解决方案是每次追加时创建 pos 的副本:

package main

import "fmt"

func main() {
    var array [][]int
    array = make([][]int, 0, 100)
    count := 0
    
    for i := 0; i < 2; i++ {
        for j := 0; j < 2; j++ {
            // 每次循环创建新的切片
            pos := []int{j, 0}
            fmt.Println("i=", i, "j=", j, "count=", count, "pos=", pos)
            
            array = append(array, pos)
            fmt.Println("appending pos=", pos, "to array")
            fmt.Println("just added", array[count])
            count++
        }
    }
    
    fmt.Println("size is", len(array))
    fmt.Println("array", array)
}

或者使用 copy 函数显式复制:

package main

import "fmt"

var array [][]int
var pos []int

func main() {
    pos = make([]int, 2)
    array = make([][]int, 0, 100)
    count := 0
    
    for i := 0; i < 2; i++ {
        for j := 0; j < 2; j++ {
            pos[0] = j
            pos[1] = 0
            fmt.Println("i=", i, "j=", j, "count=", count, "pos=", pos)
            
            // 创建副本
            posCopy := make([]int, len(pos))
            copy(posCopy, pos)
            array = append(array, posCopy)
            
            fmt.Println("appending pos=", pos, "to array")
            fmt.Println("just added", array[count])
            count++
        }
    }
    
    fmt.Println("size is", len(array))
    fmt.Println("array", array)
}

两个解决方案都会输出正确的结果:

array [[0 0] [1 0] [0 0] [1 0]]

这是因为每次追加的都是独立的数据副本,而不是同一个切片的引用。

回到顶部