Go语言中的范围(Range)
qingheluo2021-09-04清河洛454
Go语言中range关键字用于for循环中迭代核心类型为数组、指向数组的指针、slice、string、map、允许接收操作的通道在1.22版本中增加了迭代整数的功能在1.23版本充增加了迭代特定签名函数的功能如果for语句中定于的变量为两个则返回元素的索引和索引对应的值如果for语句中定义的变量为一个则返回元素的索引遍历切片:
nums := [] int {1,2,3,4,5}
for index,val := range nums {
fmt.Printf("索引 %d 的值为 %d ", index , val)
}
遍历集合:
maps := map [string] ...
Go语言中range关键字用于for循环中迭代核心类型为数组、指向数组的指针、slice、string、map、允许接收操作的通道
在1.22版本中增加了迭代整数的功能
在1.23版本充增加了迭代特定签名函数的功能
如果for语句中定于的变量为两个则返回元素的索引和索引对应的值
如果for语句中定义的变量为一个则返回元素的索引
遍历切片:
nums := [] int {1,2,3,4,5} for index,val := range nums { fmt.Printf("索引 %d 的值为 %d ", index , val) }
遍历集合:
maps := map [string] string {"name":"三千","age":"33","sex":"男"} for index,val := range maps { fmt.Printf("索引%s的值为%s", index , val) }
遍历字符串:
str := "hello" for index,val := range str { fmt.Prinft("索引%s的值为%s", index , val) } 其中val为当前索引的字符对应的int32的Unicode值
如果字符串中有中文,则该中文字符之后的一个字符索引将增加3
str := "华夏" for index,val := range str { fmt.Printf("索引%d的值为%d", index , val) } 索引0的值为21326 索引3的值为22799
遍历数字:
for i := range 10 { fmt.Println(i) // 输出0 1 2 3 4 5 6 7 8 9 } 当遍历数字时,仅可由一个变量接收,如果两个变量接收会报错 无法确定仅接收索引或仅接收值,因为索引和值相等 for i,v : = range 10 {} // 会报错
读取通道:
for val := range ch{ fmt.Println("接收到的通道值:", val) // 当通道关闭后循环结束 }
在1.22之前的版本中,for...range循环时的迭代变量只创建一次,在每次迭代中为这个变量赋予新的值,由于这个问题会出现一些意想不到的结果
demo := []int{1, 2, 3, 4, 5} for _,v := range demo { go func() { fmt.Println(v) }() } time.Sleep(time.Second) 上面代码我们预想的应该是一个协程输出1,一个协程输出2,...,一个协程输出5,但实际上却是不可预知的
由于携程函数中的变量访问是在执行打印函数时才会访问,在创建协程时并不会访问,如当迭代为3时,所有在此时刚好执行打印函数的携程都会输出3,在迭代完成后所有的协程都会输出5
针对这个问题,之前的解决办法是在携程函数中使用一个局部变量,在创建协程时将此时迭代的值传递给它,这样就可以保证每次迭代都能访问到正确的值
for _,v := range demo { go func() { newV := v fmt.Println(newV) }() } time.Sleep(time.Second) 或者 for _,v := range demo { go func(v int) { fmt.Println(v) }(v) } time.Sleep(time.Second) 这样在创建协程时就访问并传递了此时迭代的值,保证每次迭代都能访问到正确的值
在1.22版本中,官方已经修复了这个问题,现在for...range循环的迭代变量在每次迭代中都重新创建,不会出现上述问题