时间:2016-06-06 23:15:23

标签: go

我正在参加“Tour of Go”,并对Exercise: Slices example提出了疑问。目前我可以通过使用[]运算符迭代每个索引来创建图片,就像在C中一样。

func Pic(dx, dy int) [][]uint8 {
    pic := make([][]uint8, dy)
    for i := range pic {
        pic[i] = make([]uint8, dx)
        for j := range pic[i] {
            pic[i][j] = uint8(1)
        }
    }
    return pic
} 

然而,当我尝试执行以下操作时,我收到panic: runtime error: index out of range错误。我尝试添加print语句并调用Pic(3, 3),它打印出一个3x3数组就好了。

func Pic(dx, dy int) [][]uint8 {
    pic := make([][]uint8, dy)
    for _, y := range pic {
        y = make([]uint8, dx)
        for _, x := range y {
            x = uint8(1)
            _ = x // x has to be used
            //fmt.Print("1")
        }
        //fmt.Print("\n")
    }
    return pic
}

对我做错了什么的想法?

2 个答案:

答案 0 :(得分:1)

主要问题是你尝试做任务。使用您的代码检查我的示例; https://play.golang.org/p/lwoe79jQ70

实际上从后一个实现中得到的是一个3x0数组,所有内部数组都是空的。这样做的原因是因为您使用范围变量进行分配而不起作用。如果当前索引为0,则y != pic[0]pic[0]已分配给y但是,y是临时存储,它通常是相同的地址并且已结束写在每次迭代上。因此,在后一个示例执行后,所有x方向数组都为空,索引为一个会导致恐慌。

基本上你应该只是使用你的第一个实现,因为它工作正常,通常是这样做的方式。但是,当你执行a, b := range Something b != Something[a]时,它就是实例,它超出了循环底部的范围并且分配给它不会导致状态更改为集合Something,如果您要修改Something[a],则必须分配到Something[a]

答案 1 :(得分:1)

范围会复制您正在迭代的切片中的值。
请参阅:http://golang.org/ref/spec#RangeClause

为了澄清会发生什么,请参阅这个简单的代码示例及其输出:

package main

import "fmt"

func main() {
    s := "hi"
    //s[0] = 'H' // cannot assign to s[0]
    for _, v := range s {
        fmt.Printf("%T, %[1]v, %X\n", v, &v)
        v = 'H' // has no effect: this is local var not ref
    }
    fmt.Println(s)
}

输出结果为:
int32,104,C0820042D4
int32,105,C0820042D4

如您所见变量v的地址未更改(C0820042D4)且v是局部变量且范围复制值为其,因此更改v无效。 这里v是符文(int32别名),符文是一个标识Unicode代码点的整数值,你不能分配给s [0],这不会编译:s [0] ='H'
所以v ='H'对s没有影响,它只是局部变量。