本文主要介绍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]}
}