写的时候遇到个小坑。过于想当然,以为用法和java一样写就得了。单测的时候发现问题了。
在for x...:= range (slice/map) 的这种语法中,前面的x...都是临时变量,所以有时会导致一些错误。分3种情况:
- 如果就是读一个slice或者map,那无所谓,可以这么写。
- 如果想修改这个x,这时候会有问题,因为这个x只是slice/map里面存的数据的副本。
2.1 如果slice里面就是struct,用range的方式不能修改,所以应该是用slice[index]或者map[key]来修改。
2.3 如果不想那么写,那slice里面存的得是指针*struct。所以x是副本,但是指向同一个地址,所以修改x有效。 - 如果想取x的地址,但是slice/map里面又是struct,那就需要用index/key来搞;如果里面存的是pointer,那就可以直接用x赋值,因为指向的地址一样。
type Student struct {
Age int
}
func TestForLoop() {
students := []Student{{1}, {2}, {3}}
fmt.Println("wrong way:")
for i, stu := range students {
fmt.Printf("index: %d, addres:%p\n", i, &stu)
stu.Age = 100
}
fmt.Println(students)
fmt.Println("\nright way:")
for i := 0; i < len(students); i++ {
fmt.Printf("index: %d, addres:%p\n", i, &students[i])
}
fmt.Println("\nmap to struct:")
name2Student := map[string]Student{"1":{1}, "2":{2}, "3":{3}}
for name, stu := range name2Student {
fmt.Printf("index: %s, addres:%p\n", name, &stu)
stu.Age = 100
}
fmt.Println(name2Student)
fmt.Println("\nmap to pointer of struct:")
var temp *Student
name2StudentPointer := map[string]*Student{"1":{1}, "2":{2}, "3":{3}}
for name, stu := range name2StudentPointer {
fmt.Printf("index: %s, addres:%p\n", name, &stu)
stu.Age = 100
if name == "1" {
temp = stu
}
}
fmt.Printf("%+v\n", name2StudentPointer["1"])
fmt.Println("\nmodify by temp pointer:")
fmt.Println(temp.Age)
temp.Age = 10
fmt.Printf("%+v\n", name2StudentPointer["1"])
}
func main() {
TestForLoop()
}
output:
wrong way:
index: 0, addres:0xc42001e4c0
index: 1, addres:0xc42001e4c0
index: 2, addres:0xc42001e4c0
[{1} {2} {3}]
right way:
index: 0, addres:0xc42001c380
index: 1, addres:0xc42001c388
index: 2, addres:0xc42001c390
map to struct:
index: 1, addres:0xc42001e518
index: 2, addres:0xc42001e518
index: 3, addres:0xc42001e518
map[3:{3} 1:{1} 2:{2}]
map to pointer of struct:
index: 1, addres:0xc42000e038
index: 2, addres:0xc42000e038
index: 3, addres:0xc42000e038
&{Age:100}
modify by temp pointer:
100
&{Age:10}
Process finished with exit code 0