range是go提供的一种迭代遍历手段。 range遍历

range遍历可操作的类型有数组(包括字符串)、切片、Map、channel等:

for i := range arraysfor k := range mapsfor range collections
func rangeIndexOnly() {
	v := []int{10, 20, 30}
	for i := range v {
		v[i] *= 2
	}
	fmt.Println(v)
}

func rangeKeyOnly() {
	fruits := map[string]string{"a": "apple", "b": "banana"}
	for k := range fruits {
		fmt.Printf("%s\n", k)
	}
}

func rangeOnly() {
	var Counts [5][0]int // no memory occupy
	for range Counts { // 五次循环
		fmt.Println("Range-Count")
	}
}
[0]int

遍历slice

遍历slice前,会先获取其长度作为循环次数;循环体中,每次循环会先获取元素值,若需要index与value的话,则进行赋值;

遍历切片的伪码:

// for_temp := range-slice
// len_temp := len(for_temp)
// for index_temp = 0; index_temp < len_temp; index_temp++ {
// 		value_temp = for_temp[index_temp]
// 		index = index_temp
// 		value = value_temp
// 		original body
// }

循环开始前循环次数就已经确定了, 所以循环过程中新添加的元素是不会被遍历到的。

ary[index]

遍历数组、切片时,返回(index, value):

    nums := []int{2, 3, 4}
    sum := 0
    for _, num := range nums {
        sum += num
    }

遍历map

map底层使用hash表实现,插入数据位置是随机的,所以遍历过程中新插入的数据不能保证遍历到(可能会被遍历到,也可能遍历不到)。

遍历map的伪码:

// var hiter map_iteration_struct
// for mapiterinit(type, range, &hiter); hiter.key != nil; mapiternext(&hiter) {
// 		key_temp = *hiter.key
// 		value_temp = *hiter.val
// 		key = key_temp
// 		value = value_temp
// 		original body
// }

遍历map时,返回(key,value):

    fruits := map[string]string{"a": "apple", "b": "banana"}
    for k, v := range fruits {
        fmt.Printf("%s -> %s\n", k, v)
    }

遍历channel

channel是依次从通道中读取数据:

  • 如果通道中没有元素,则会阻塞等待;
  • 如果channel已被关闭,则会解除阻塞并退出循环;

遍历通道伪码:

// for {
// 	value_temp, ok_temp = <-range
// 	if !ok_temp {
// 		break
// 	}
// 	value = value_temp
// 	original body
// }

遍历channel时,返回接收到的数据:

    ch := make(chan int) 
 
    // 发送数据的goroutine
    go func() {
        for i := 0; i < 5; i++ {
            ch <- i+1 //往通道写数据
        }
        
        //不需要再写数据时,关闭channel
        close(ch) 
    }()
 
    for num := range ch {
        fmt.Println("num = ", num)
    }