我正在参加“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
}
对我做错了什么的想法?
答案 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没有影响,它只是局部变量。