本篇参考自:https://blog.csdn.net/somanlee/article/details/107881231,尊重原创
废话就不说了,先来一段代码:
package main
import (
"fmt"
)
func main() {
slice := []int{0, 1, 2, 3}
mp := make(map[int]*int)
for index, value := range slice {
mp[index] = &value
}
fmt.Println("-------------------------------------------------------------------")
for key, value := range mp {
fmt.Println(key, " ", *value)
}
}
先猜一下输出的结果是什么,再看看结果跟你想的是不是一样的
没错,全都是 333333,就差个2了
其根本原因就是 for range是用一个变量承接rang 后面的内容,也就是上面的mp,slice,什么意思???
我们先看看为什么全都是3,稍微做出一点改变:
func main() {
slice := []int{0, 1, 2, 3}
mp := make(map[int]*int)
for index, value := range slice {
mp[index] = &value
fmt.Println("address is:",&value)
fmt.Println("value is:",value)
}
//根本原因在于for range是用一个变量承接mp中的内容的
fmt.Println("-------------------------------------------------------------------")
for key, value := range mp {
fmt.Println(key, " ", *value)
}
}
结果如下:
有没有发现,为什么地址都是一样的,而最后这个地址的值是3,mp中存的是又是这个地址,所以不全都是3了嘛。那又为什么会是这样了呢?上文中的承接是什么意思呢??
for range
for index, value := range t_slice {
original body
}
相当于:
len_temp := len(t_slice)
range_temp := t_slice
for index_temp = 0; index_temp < len_temp; index_temp++ {
value_temp := range_temp[index_temp]
index := index_temp
value := value_temp
original body
}
这个承接的变量就是 range_temp。
正确的写法:
package main
import (
"fmt"
)
func main() {
slice := []int{0, 1, 2, 3}
mp := make(map[int]*int)
for index, value := range slice {
num := value
mp[index] = &num
// mp[index] = &slice[index] 用切片的index也行
}
//根本原因在于for range是用一个变量承接mp中的内容的
fmt.Println("-------------------------------------------------------------------")
for key, value := range mp {
fmt.Println(key, " ", *value)
}
}
在for range中启动携程:
package main
import (
"fmt"
"sync"
)
func main() {
var m = []int{1, 2, 3}
var wg sync.WaitGroup
for i := range m {
wg.Add(1)
go func() {
fmt.Print(i)
wg.Done()
}()
}
wg.Wait()
}
输出结果为:222
上面的代码中,每轮循环中使用匿名函数起协程,匿名函数直接引用外部变量i,实际上,这就是golang中的闭包,闭包是匿名函数与匿名函数所引用环境的组合,匿名函数有动态创建的特性,这使得匿名函数不用通过参数传递的方式,就可以直接引用外部的变量。
每轮循环启动一个协程,而协程启动与循环变量递增不是在同一个协程,协程启动的速度远小于循环执行的速度,所以即使是第一个协程刚起启动时,循环变量可能已经递增完毕。由于所有的协程共享循环变量i,而且这个i会在最后一个使用它的协程结束后被销毁,所以最后的输出结果都是循环变量的末值即2。
添加延时,确保协程启动:
package main
import (
"fmt"
"sync"
"time"
)
func main() {
var wg sync.WaitGroup
var m = []int{1, 2, 3}
for i := range m {
wg.Add(1)
go func() {
fmt.Print(i)
wg.Done()
}()
time.Sleep(time.Second)
}
wg.Wait()
}
传入参数:
package main
import (
"fmt"
"sync"
)
func main() {
var m = []int{1, 2, 3}
var wg sync.WaitGroup
for i := range m {
wg.Add(1)
go func(i int) {
fmt.Print(i)
wg.Done()
}(i)
}
wg.Wait()
}
局部变量:
package main
import (
"fmt"
"sync"
)
func main() {
var m = []int{1, 2, 3}
var wg sync.WaitGroup
for i := range m {
wg.Add(1)
n := i
go func() {
fmt.Print(n)
wg.Done()
}()
}
wg.Wait()
}
每次for的时候n都是不同的变量