语言规范
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.
- 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 tolen(a)-1
and does not index into the array or slice itself. For anil
slice, the number of iterations is 0.- 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 be0xFFFD
, the Unicode replacement character, and the next iteration will advance a single byte in the string.- 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.- 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
-
清空内容
-
表现形式
for i := range a { a[i] = E0 // 对应类型的0值 }
-
背后本质(需要满足一定条件,如果不满足则退化为单初始变量的场景)
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 }
-
-
无初始变量
-
表现形式
for range a { // 实际业务 }
-
背后本质
ha := a for hv1, hn := 0, len(ha); hv1 < hn; hv1++ { // 实际业务 }
-
-
单初始变量
-
表现形式
for i := range a { // 实际业务 }
-
背后本质
var i int ha := a for hv1, hn := 0, len(ha); hv1 < hn; hv1++ { i = hv1 // 实际业务 }
-
-
双初始变量,可优化型
-
表现形式
for i, v := range a { // 实际业务 }
-
背后本质
var i int var v E ha := a for hv1, hn := 0, len(ha); hv1 < hn; hv1++ { i, v = hv1, ha[hv1] // 实际业务 }
-
-
双初始变量,一般情况
-
表现形式
for i, v := range a { // 实际业务 }
-
背后本质
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
-
清空内容
-
表现形式
for k := range m { delete(m, k) }
-
背后本质(需要满足一定条件,如果不满足则退化为单初始变量的场景)
runtime.mapclear(t *maptype, h *hmap)
-
-
无初始变量
-
表现形式
for range m { // 业务代码 }
-
背后本质
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 // 业务代码 }
-
-
单初始变量
-
表现形式
for k := range m { // 业务代码 }
-
背后本质
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 // 业务代码 }
-
-
双初始变量
-
表现形式
for k, v := range m { // 业务代码 }
-
背后本质
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
-
无初始变量
-
表现形式
for range c { // 业务代码 }
-
背后本质
hc := c for hv1, hb := <-hc; hb != false; hv1, hb = <-hc { hv1 = E0 // 对应类型的0值 // 业务代码 }
-
-
单初始变量
-
表现形式
for v := range c { // 业务代码 }
-
背后本质
var v E hc := c for hv1, hb := <-hc; hb != false; hv1, hb := <-hc { v = hv1 hv1 = E0 // 对应类型的0值 // 业务代码 }
-
字符串:string
-
无初始变量
-
表现形式
for range s { // 业务代码 }
-
背后本质
hs := s for hv1 := 0; hv1 < len(hs); { hv2 := rune(hs[hv1]) if hv2 < utf8.RuneSelf { hv1++ } else { hv2, hv1 = runtime.decoderune(hs, hv1) } // 实际业务 }
-
-
单初始变量
-
表现形式
for i := range s { // 实际业务 }
-
背后本质
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 // 实际业务 }
-
-
双初始变量
-
表现形式
for i, v := range s { // 实际业务 }
-
背后本质
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 // 实际业务 }
-