比如要实现从0到9的打印,需求很简单
原则1: 协程是共享函数的变量的,换句话说:在一个函数中,如果有一个协程,这个协程是可以使用这个函数的变量的。
如下这个执行有问题
```go
func shadow() {
for i := 0; i < 10; i++ {
go func() {
fmt.Println(i) //Question1: 为什么i取不到上面i的值?不是说好协程共享函数的变量的吗,现在怎么背叛我了?
}()
}
time.Sleep(time.Second)
}
```
需要改成如下才行:
```go
func shadow() {
for i := 0; i < 10; i++ {
go func(i int) {
fmt.Println(i)
}(i) //Question2: 问题跟上面类型,背叛了原则1。因它取不到 i的值。
}
time.Sleep(time.Second)
}
```
或是,如下也是可以的
```go
func scope() {
for i := 0; i < 10; i++ {
i := i //需要加上这个语句,才会从0打印到9;否则打印的不是预期
go func() {
fmt.Println(i)
}()
}
time.Sleep(time.Second)
}
```
下面这个示例是对*原则1*的证明,协程确实是共享函数的变量的。
```go
c := make(chan int)
go func() {
time.Sleep(time.Second * 1)
c <- 10 //Question3: 像这里的c它其实是go func外部的变量。但是协程里面,为什么这里又不是个func{}这个函数中的局部变量?为什么这里不需要通过传参的形式来实现?
close(c)
}()
for {
select {
default:
fmt.Printf("%v No Output, now is default\n", time.Now().Format(fmat))
case x, ok := <-c:
fmt.Printf("%v, Now step into chan, x:%v, ok:%v\n", time.Now().Format(fmat), x, ok)
time.Sleep(time.Second * 5)
}
}
```
但是为什么在for range中协程取不到函数的变量呢?
更多评论
这里关键点在于for k,v range{ go func(){ k }()} ,这个循环内部是局部变量,需要在循环体内定义一个局部变量接收k,v的值,然后go func这个闭包引用外部变量的时候就可以使用这个局部变量,不然每次用的变量都是外部的变量。
总而言之:for range是有内部作用域的。
#2