您的位置 首页 golang

golang的range其实很简单

说明:

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

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

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

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

第一点:range的对象,

首先range后的操作对象,是一个数据拷贝,而不是在原始(或者代码上文)类型上操作的。那么拷贝的是什么呢?这要根据具体数据类型也看,range的对象可以分为两种数据类型,一个是值类型(例如:array 、string),一个是引用类型 (slice、map、channel)。值类型就是值拷贝,引用类型就是引用拷贝。这里边还有一个指针,指针的表现跟引用类型一致。

看个例子吧:

 package main

import (
  "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 main

import (
"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 <- &v

temp := 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: 5
cha: 5
cha: 5
cha: 5
cha: 5
--------------------------
chb: 1
chb: 2
chb: 3
chb: 4
chb: 5  

关于闭包捕获变量的表现请看:

文章来源:智云一二三科技

文章标题:golang的range其实很简单

文章地址:https://www.zhihuclub.com/97071.shtml

关于作者: 智云科技

热门文章

网站地图