开发人员在日常开发中经常会遇到for range循环需求,因其类型的特殊性,用起来有别于其他语言,需要注意,这里对map、切片、数组循环遇到常见问题进行整理。
1、for range map 在开始执行循环的时候,底层做了随机种子,故其循环是随机的。
package main
import "fmt"
func main() {
a := map[int]int{0: 1, 1: 2, 2: 3, 3: 4, 4: 5}
for _, c := range a {
fmt.Println(c)
}
}
输出:
3
4
5
1
2
多次执行,结果不同
package main
import "fmt"
func main() {
a := [5]int{0: 1, 1: 2, 2: 3, 3: 4, 4: 5}
for b, c := range a {
if b == 0 {
a[1] = 22
//fmt.Println(b)
}
a[b] = c + 10
}
fmt.Println(a)
}
输出:
[11 12 13 14 15]
//a[1] = 22 并没有起作用,因数组是值类型,使用range获取的数组项是复制过来的,并非引用原始数据。
如果想a[1] = 22 有效,只需改成引用。
package main
import "fmt"
func main() {
a := [5]int{0: 1, 1: 2, 2: 3, 3: 4, 4: 5}
for b, c := range &a {//注意此处改变
if b == 0 {
a[1] = 22
//fmt.Println(b)
}
a[b] = c + 10
}
fmt.Println(a)
}
结果:
[11 32 13 14 15]
slice 是引用类型,底层指针指向数组,传参的时候传引用和传值区别不大。
package main
import "fmt"
func main() {
a := []int{0: 1, 1: 2, 2: 3, 3: 4, 4: 5}
for b, c := range a {
if b == 0 {
a[1] = 22
//fmt.Println(b)
}
a[b] = c + 10
}
fmt.Println(a)
}
结果:
[11 32 13 14 15]
对比上一个例子,不需要传引用就可以更改a[1] = 22
这个是输出异常的示例
package main
import (
"fmt"
)
func main() {
a := []int{1, 2, 3}
b := make([]*int, len(a))
for i, v := range a {
//解决办法1增加临时变量
//vv := v
//b[i] = &vv
//解决办法2
//b[i] = &a[i]
b[i] = &v
}
for _, v := range b {
fmt.Println(*v)
}
}
输出:
3
3
3
原因v变量在for range中只会创建一次,之后迭代重复使用
package main
import (
"fmt"
"time"
)
func main() {
a := []int{0: 1, 1: 2, 2: 3, 3: 4, 4: 5}
for _, c := range a {
go func() {
fmt.Println(c)
}()
}
time.Sleep(3 * time.Second)
}
结果为:
3
3
5
5
5
有两种方法解决以上问题
1、增加一个临时变量
package main
import (
"fmt"
"time"
)
func main() {
a := []int{0: 1, 1: 2, 2: 3, 3: 4, 4: 5}
for _, c := range a {
cc:=c //增减临时变量cc
go func() {
fmt.Println(cc)
}()
}
time.Sleep(3 * time.Second)
}
2、 传参进去
package main
import (
"fmt"
"time"
)
func main() {
a := []int{0: 1, 1: 2, 2: 3, 3: 4, 4: 5}
for _, c := range a {
go func(c int) {
fmt.Println(c)
}(c)
}
time.Sleep(3 * time.Second)
}
package main
import (
"fmt"
"time"
)
type v struct {
value int
}
func (vv *v) show() {
fmt.Println(vv.value)
}
func main() {
a := []v{{1}, {2}, {3}}
for _, c := range a {
go c.show()
}
time.Sleep(3 * time.Second)
}
输出:
3
3
3
解决办法
1、增加临时变量
package main
import (
"fmt"
"time"
)
type v struct {
value int
}
func (vv *v) show() {
fmt.Println(vv.value)
}
func main() {
a := []v{{1}, {2}, {3}}
for _, c := range a {
c := c //增加这一行
go c.show()
}
time.Sleep(3 * time.Second)
}
2、使用指针
package main
import (
"fmt"
"time"
)
type v struct {
value int
}
func (vv *v) show() {
fmt.Println(vv.value)
}
func main() {
a := []*v{{1}, {2}, {3}}
for _, c := range a {
go c.show()
}
time.Sleep(3 * time.Second)
}
3、方法show接受者不用指针
package main
import (
"fmt"
"time"
)
type v struct {
value int
}
func (vv v) show() {
fmt.Println(vv.value)
}
func main() {
a := []v{{1}, {2}, {3}}
for _, c := range a {
go c.show()
}
time.Sleep(3 * time.Second)
}