Go-map、切片、数组循环常见问题总结

发布时间 2023-06-16 10:36:12作者: minch

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

slice 是引用类型,底层指针指向数组,传参的时候传引用和传值区别不大。

示例1

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

示例2

这个是输出异常的示例

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接受者不用指针