一个Golang遍历切片常犯的错误

type Person struct {
    age int
}

func f5(arr []Person) []*Person {
    var personRefSet []*Person
    for _, person := range arr {
        personRefSet = append(personRefSet, &person)
    }
    return personRefSet
}

func main() {
    originArr := []Person{
        {age: 1},
        {age: 2},
    }
    refArr := f5(originArr)
    for _, refPerson := range refArr {
        println(refPerson)
    }
}


输出结果:

0xc0002271c0
0xc0002271c0

从结果来看refArr的每个元素都是相同的。

为了进一步弄清原理,写了以下代码:

func f5(arr []Person) []*Person {
	var personRefSet []*Person
	for i, person := range arr {
		personRefSet = append(personRefSet, &person)
		println("get addr by Index:", &arr[i])
		println("get temporary object addr by object:", &person)
	}
	return personRefSet
}

func main() {
	originArr := []Person{
		{age: 1},
		{age: 2},
	}

	refArr := f5(originArr)
	println("-----分割线----")
	for i, personRef := range refArr {
		println("refArr element(pointer type) value:", personRef)
		println("refArr element pointer's addr:", &refArr[i])
	}
}

输出:

get addr by Index: 0xc000187f38
get temporary object addr by object: 0xc0002271c0
get addr by Index: 0xc000187f40
get temporary object addr by object: 0xc0002271c0
-----分割线----
refArr element(pointer type) value: 0xc0002271c0
refArr element pointer's addr: 0xc000229120
refArr element(pointer type) value: 0xc0002271c0
refArr element pointer's addr: 0xc000229128

其中:
get addr by Index: 0xc000187f38打印的是通过元素下标获取的元素的地址值
get temporary object addr by object: 0xc0002271c0打印的是当前循环中的临时对象的地址值

refArr element(pointer type) value打印的是遍历的指针变量的值(指针类型比较特殊,它的值就是一个地址值,用这个地址引用或者说存储一个对象)
refArr element pointer's addr打印的是通过下标获取的指针变量的地址

 

通过这一次探索,对指针和地址值有了新的认识:
地址值是对象在内存中的id,是一个16进制数;
指针是一种变量类型,它保存另一个对象的地址值,指针变量的值就是一个地址值。指针变量自己也是一个对象,也有自己的地址值,理论上就可以套娃,但没有实际意义。

 

posted @ 2023-05-15 21:29  MajorDeng  阅读(44)  评论(0)    收藏  举报