说明:

要搞明白range其实很简单,除了简单使用方式外,只需要搞明白两个问题就OK了

第一:range会复制对象、所以得明白range后面操作的对象是谁,

第二:range通过操作符 := 创建的对象是怎么回事,是一次创建还是每次循环都创建新的

弄明白这两点,就真正弄明白了range方法的所有表现

第一点:range的对象,

首先range后的操作对象,是一个数据拷贝,而不是在原始(或者代码上文)类型上操作的。

那么拷贝的是什么呢?这要根据具体数据类型也看,range的对象可以分为两种数据类型,一个是值类型(例如:array 、string),一个是引用类型 (slice、map、channel)。

值类型就是值拷贝,引用类型就是引用拷贝。

这里边还有一个指针,指针的表现跟引用类型一致。

看个例子吧:

package mainimport (  "fmt")func main() {  // 值类型应用range方法  var array = [5]int{1, 2, 3, 4, 5}  var array_new [5]int  fmt.Println("原始数组的值:", array)  for index, value := range array {    if index == 0 { // 当遍历第一个元素时修改原始数组中的值      array[1] = 10 * value // 此array跟range后边的array已经不是一个值了      array[2] = 20 * value // 此array跟range后边的array已经不是一个值了    }    array_new[index] = value  }  fmt.Println("原始数组改变后的值:", array)  fmt.Println("依托原始数组创建的新数组的值:", array_new) // 新数组是根据值拷贝创建的,会跟原始数组一致  fmt.Println("--------------------------")  // 引用类型应用range方法  var slice_src = []int{1, 2, 3, 4, 5}  var slice_des = make([]int, 5)  fmt.Println("原始切片的值:", slice_src)  for index, value := range slice_src {    if index == 0 { // 当遍历第一个元素时修改原始切片中的值      slice_src[1] = 10 * value // 此slice_src跟range后边的slice_src指向同一块内存,浅拷贝,引用复制      slice_src[2] = 20 * value // 此slice_src跟range后边的slice_src指向同一块内存,浅拷贝,引用复制            slice_src = append(slice_src, 6, 7, 8, 9) // 印证range 后边slice_src也是一个拷贝    }    slice_des[index] = value  }  fmt.Println("原始切片改变后的值:", slice_src)  fmt.Println("依托原始切片创建的新切片的值:", slice_des) // 新切片是根据引用复制创建的,会跟改变后的切片一致}

响应结果:

原始数组的值: [1 2 3 4 5]原始数组改变后的值: [1 10 20 4 5]依托原始数组创建的新数组的值: [1 2 3 4 5]--------------------------原始切片的值: [1 2 3 4 5]原始切片改变后的值:  [1 10 20 4 5 6 7 8 9]依托原始切片创建的新切片的值: [1 10 20 4 5]

第二点:range通过操作:=创建变量是一次性的

range跟for搭配,是一个循环操作。但是操作符:=前边的变量确不是每次初始化,它只在第一次的时候分配内存,后边不论循环多少次都是修改该内存的值。

看个例子吧:

package mainimport ("fmt")func main() {var array = [5]int{1, 2, 3, 4, 5}var cha = make(chan *int, 5)var chb = make(chan *int, 5)go func() { // 匿名函数、闭包for _, v := range array { // 在整个循环过程中,v只声明了一次,后续循环都是更改v的值cha <- &vtemp := v // 在每次循环中,temp都被重新声明,从新分配内存地址chb <- &temp}close(cha)close(chb)}()for v := range cha {fmt.Println("cha:", *v) // 都是最后一个值5}fmt.Println("--------------------------")for v := range chb {fmt.Println("chb:", *v) // 输出1,2,3,4,5}}

响应结果:

cha: 5cha: 5cha: 5cha: 5cha: 5--------------------------chb: 1chb: 2chb: 3chb: 4chb: 5

关于闭包捕获变量的表现请看:Golang匿名函数与闭包