Golang range原理分析

语言规范

A “for” statement with a “range” clause iterates through all entries of an array, slice, string or map, or values received on a channel. For each entry it assigns iteration values to corresponding iteration variables if present and then executes the block.

  1. For an array, pointer to array, or slice value a, the index iteration values are produced in increasing order, starting at element index 0. If at most one iteration variable is present, the range loop produces iteration values from 0 up to len(a)-1 and does not index into the array or slice itself. For a nil slice, the number of iterations is 0.
  2. For a string value, the “range” clause iterates over the Unicode code points in the string starting at byte index 0. On successive iterations, the index value will be the index of the first byte of successive UTF-8-encoded code points in the string, and the second value, of type rune, will be the value of the corresponding code point. If the iteration encounters an invalid UTF-8 sequence, the second value will be 0xFFFD, the Unicode replacement character, and the next iteration will advance a single byte in the string.
  3. The iteration order over maps is not specified and is not guaranteed to be the same from one iteration to the next. If a map entry that has not yet been reached is removed during iteration, the corresponding iteration value will not be produced. If a map entry is created during iteration, that entry may be produced during the iteration or may be skipped. The choice may vary for each entry created and from one iteration to the next. If the map is nil, the number of iterations is 0.
  4. For channels, the iteration values produced are the successive values sent on the channel until the channel is closed. If the channel is nil, the range expression blocks forever.

数组、数组指针、切片:[n]E, *[n]E, or []E

  1. 清空内容

    1. 表现形式

      for i := range a {
          a[i] = E0 // 对应类型的0值
      }
      
    2. 背后本质(需要满足一定条件,如果不满足则退化为单初始变量的场景

      if len(a) != 0 {
          hp := unsafe.Pointer(&a[0])          // 从该位置起
          hn := len(a) * unsafe.Sizeof(E)      // 清除hn个字节的内存
          runtime.memclrNoHeapPointers(hp, hn) // 如果E不包含堆指针
          runtime.memclrHasPointers(hp, hn)    // 如果E包含堆指针
          i = len(a) - 1
      }
      
  2. 无初始变量

    1. 表现形式

      for range a {
          // 实际业务
      }
      
    2. 背后本质

      ha := a
      for hv1, hn := 0, len(ha); hv1 < hn; hv1++ {
          // 实际业务
      }
      
  3. 单初始变量

    1. 表现形式

      for i := range a {
          // 实际业务
      }
      
    2. 背后本质

      var i int
      ha := a
      for hv1, hn := 0, len(ha); hv1 < hn; hv1++ {
          i = hv1
          // 实际业务
      }
      
  4. 双初始变量,可优化型

    1. 表现形式

      for i, v := range a {
          // 实际业务
      }
      
    2. 背后本质

      var i int
      var v E
      ha := a
      for hv1, hn := 0, len(ha); hv1 < hn; hv1++ {
          i, v = hv1, ha[hv1]
          // 实际业务
      }
      
  5. 双初始变量,一般情况

    1. 表现形式

      for i, v := range a {
          // 实际业务
      }
      
    2. 背后本质

      var i int
      var v E
      tmp := ha[0]
      if hv1, hn, hp := 0, len(ha), &tmp; hv1 < hn {
          top:
          i, v = hv1, *hp
          // 业务代码
          hv1++
          if hv1 < hn {
              hp += unsafe.SizeOf(E)
              goto top
          }
      }
      

哈希:map[K]V

  1. 清空内容

    1. 表现形式

      for k := range m {
          delete(m, k)
      }
      
    2. 背后本质(需要满足一定条件,如果不满足则退化为单初始变量的场景

      runtime.mapclear(t *maptype, h *hmap)
      
  2. 无初始变量

    1. 表现形式

      for range m {
          // 业务代码
      }
      
    2. 背后本质

      hm := m
      hit := prealloc[n]
      // t *maptype, h *hmap, it *hiter
      for runtime.mapiterinit(t, h, it); hit.key != nil; runtime.mapiternext(it) {
          key := *hit.key
          // 业务代码
      }
      
  3. 单初始变量

    1. 表现形式

      for k := range m {
          // 业务代码
      }
      
    2. 背后本质

      var k K
      hm := m
      hit := prealloc[n]
      // t *maptype, h *hmap, it *hiter
      for runtime.mapiterinit(t, h, it); hit.key != nil; runtime.mapiternext(it) {
          key := *hit.key
          k = key
          // 业务代码
      }
      
  4. 双初始变量

    1. 表现形式

      for k, v := range m {
          // 业务代码
      }
      
    2. 背后本质

      var k K
      var v V
      hm := m
      hit := prealloc[n]
      // t *maptype, h *hmap, it *hiter
      for runtime.mapiterinit(t, h, it); hit.key != nil; runtime.mapiternext(it) {
          key := *hit.key
          elem := *hit.elem
          k, v = key, elem
          // 业务代码
      }
      

信道:chan E, <-chan E

  1. 无初始变量

    1. 表现形式

      for range c {
          // 业务代码
      }
      
    2. 背后本质

      hc := c
      for hv1, hb := <-hc; hb != false; hv1, hb = <-hc {
          hv1 = E0 // 对应类型的0值
          // 业务代码
      }
      
  2. 单初始变量

    1. 表现形式

      for v := range c {
          // 业务代码
      }
      
    2. 背后本质

      var v E
      hc := c
      for hv1, hb := <-hc; hb != false; hv1, hb := <-hc {
          v = hv1
          hv1 = E0 // 对应类型的0值
          // 业务代码
      }
      

字符串:string

  1. 无初始变量

    1. 表现形式

      for range s {
          // 业务代码
      }
      
    2. 背后本质

      hs := s
      for hv1 := 0; hv1 < len(hs); {
          hv2 := rune(hs[hv1])
          if hv2 < utf8.RuneSelf {
              hv1++
          } else {
              hv2, hv1 = runtime.decoderune(hs, hv1)
          }
          // 实际业务
      }
      
  2. 单初始变量

    1. 表现形式

      for i := range s {
          // 实际业务
      }
      
    2. 背后本质

      var i int
      hs := s
      for hv1 := 0; hv1 < len(hs); {
          hv1t := hv1
          hv2 := rune(hs[hv1])
          if hv2 < utf8.RuneSelf {
              hv1++
          } else {
              hv2, hv1 = runtime.decoderune(hs, hv1)
          }
          i = hv1t
          // 实际业务
      }
      
  3. 双初始变量

    1. 表现形式

      for i, v := range s {
          // 实际业务
      }
      
    2. 背后本质

      var i int
      var v rune
      hs := s
      for hv1 := 0; hv1 < len(hs); {
          hv1t := hv1
          hv2 := rune(hs[hv1])
          if hv2 < utf8.RuneSelf {
              hv1++
          } else {
              hv2, hv1 = runtime.decoderune(hs, hv1)
          }
          i, v = hv1t, hv2
          // 实际业务
      }
      
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值