range遍历指针类型时注意事项

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
package main

import "fmt"

func main() {
arr := []int{1,2,3,4,5,6,7,8}
odd := make([]int, 0, 5)

for _, v := range arr{
if v % 2 == 1{
odd = append(odd, v)
}
}

for _, v := range odd{
fmt.Println(v)
}
}

/*
output:
1
3
5
7
*/
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
package main

import "fmt"

func main() {
arr := []int{1,2,3,4,5,6,7,8}
**odd := make([]*int, 0, 5)**

for _, v := range arr{
if v % 2 == 1{
**odd = append(odd, &v)**
}
}

for _, v := range odd{
**fmt.Println(*v)**
}
}

/*
output:
8
8
8
8
*/

上面的区别主要是slice里面装的是标准类型还是指针类型,标准类型可以得到正常结果,而指针类型则得到重复的结果


The Go Programming Language Specification

根据Go range的文档中得到

The iteration variables may be declared by the “range” clause using a form of short variable declaration (:=). In this case their types are set to the types of the respective iteration values and their scope is the block of the “for” statement; they are re-used in each iteration. If the iteration variables are declared outside the “for” statement, after execution their values will be those of the last iteration.

变量在迭代中会重复使用,如果变量声明在for外,那么迭代结束后变量值为最后一次赋值。

因为变量v被重复使用,而它的地址不会变更。

那么上面指针类型的得到错误的结果原因也是这个


解决方法主要有两个:

  1. 使用下标

    1
    2
    3
    4
    5
    for i, _ := range arr{
    if arr[i] % 2 == 1{
    odd = append(odd, &arr[i])
    }
    }
  2. 使用临时变量

    1
    2
    3
    4
    5
    6
    for _, v := range arr{
    if v % 2 == 1{
    tmp := v
    odd = append(odd, &tmp)
    }
    }