Golang基础篇-for-range

1,144 阅读2分钟

本文主要介绍Go语言中for-range在工作编码过程中常遇到的预期之外的结果造成的困扰;文中如有描述不对或则不合理的地方,请各位大佬积极留言,我会每日及时查看并核查纠正。

使用方式

  • 四种常用的写法
func test() {
	arr := []int{1, 2, 3, 4}
	for index := range arr {
		fmt.Println(index)  // 0, 1, 2, 3
	}

	for index, value := range arr {
		fmt.Println(index, value)  // 0, 1 / 1, 2 / 2, 3 / 3, 4
	}

	// 不建议这样使用 g-lint:警告 should omit 2nd value from range; this loop is equivalent to `for index := range 
	for index, _ := range arr {
		fmt.Println(index)
	}

	for _, value := range arr {
		fmt.Println(value)  // 1, 2, 3, 4
	}
}

工作中第一个预期之外的现象

func test0001() {
	arr := []int{1, 2, 3, 4}
	for index := range arr {
		arr[index]++
	}
	fmt.Println(arr)  // 2, 3, 4, 5
}

func test0002() {
	arr := []int{1, 2, 3, 4}
	for i := 0; i < len(arr); i++ {
		arr[i]++
	}
	fmt.Println(arr)  // [2, 3, 4, 5]
}

func test0003() {
	arr := []int{1, 2, 3, 4}
	for _, value := range arr {
		value++
	}
	fmt.Println(arr)  // [1, 2, 3, 4]
}

工作中第二个预期之外的现象

func printMap(data map[int]*int) {
	for key, value := range data {
		fmt.Printf("data[%d] = %v\n", key, *value)
	}
}

func test0004() {
	arr := []int{1, 2, 3, 4}
	data := make(map[int]*int)

	for index, value := range arr {
		data[index] = &value
	}
	printMap(data)  // {0:4, 1:4, 2:4, 3:4}  无序的
}

func test0005() {
	arr := []int{1, 2, 3, 4}
	data := make(map[int]*int)

	for index, value := range arr {
		temp := value
		data[index] = &temp
	}
	printMap(data)  // {0:1, 1:2, 2:3, 3:4} 无序的
}

原理实现

  • 内部维护index, value两个全局变量
func fakeRange(arr []int, data map[int]*int) {
	// for range 核心思想是在内部构建两个全局变量
	var rangeValue int
	var rangeLen int = len(arr)
	for i := 0; i < rangeLen; i++ {
		rangeValue = arr[i]
		data[i] = &rangeValue
	}
	printMap(data)
}

func test0006() {
	arr := []int{1, 2, 3, 4}
	data := make(map[int]*int)
	fakeRange(arr, data)  // {0:4, 1:4, 2:4, 3:4} 无序的
}

再看看一个期望之外的现象

func test0007() {
	/*
	current arr value : [1 2 3 4 5 6 7 8], index : 0
	current arr value : [2 3 4 5 6 7 8], index : 1
	current arr value : [2 4 5 6 7 8], index : 2
	current arr value : [2 4 6 7 8], index : 3
	current arr value : [2 4 6 8], index : 4
	panic: runtime error: slice bounds out of range [5:4]
	*/
	arr := []int{1, 2, 3, 4, 5, 6, 7, 8}
	for index := range arr {
		fmt.Printf("current arr value : %v, index : %d\n", arr, index)
		arr = append(arr[:index], arr[index+1:]...)
	}
}

最后一个期望之外的现象

  • 切片的实现原理 + for-range实现原理
type person struct {
	ID int
	lessonIDS []int
}

func (p person) removeLessonID(ID int) {
	for index, value := range p.lessonIDS {
		if ID == value {
			p.lessonIDS = append(p.lessonIDS[:index], p.lessonIDS[index+1:]...)
		}
	}
	fmt.Printf("remove ing value : %v\n", p)  // {1, [0, 1, 2, 3, 4, 5, 7, 8]}
}

func test0008() {
	p := person{
		ID: 1,
		lessonIDS: []int{0, 1, 2, 3, 4, 5, 6, 7, 8},
	}
	fmt.Printf("remove before value : %v\n", p)  // {1, [0, 1, 2, 3, 4, 5, 6, 7, 8]}
	p.removeLessonID(6)
	fmt.Printf("remove after value : %v\n", p)  // {1, [0, 1, 2, 3, 4, 5, 6, 8, 8]}
}