新人求教:一个关于Go指针的问题

ticsmtc · · 992 次点击
详细分析后发现了应该是append的问题,之前注意力一直没有认为是appned的问题。 `tree` 在 每一次 appned 之后,`tree` 中的元素地址都会改变,应该是动态分配空间的锅。所以标记1地方的地址实际上当时是`tree`的地址,后续就不是了。当所有 `tree` 元素 append 完之后,标记2位置在进行 `points` 的赋值,这时候后续 `tree` 不再操作了,内存地址就不改变了,当然就成功了。至于为什么最后两个元素调整过程中不变化,应该是go调整内存的时候的算法问题了,有空再深究。 之前调试的时候太过注意阶段成果,没有注意到append之后动态地址变化的问题,这次算是加深印象了。。。 所以go的指针应该还是指哪打哪的,不存在说内存地址一样修改不了的问题,是我的误解。。。 还是谢谢解答!问题解决了。
#5
更多评论
我觉得你可能正好触发了一个golang的优化陷阱 考察以下代码 ```go package main import "fmt" func main() { slist := SimpleTest() fmt.Printf("%+#v\n", slist) } type S struct { Data int Children []S } func SimpleTest() (tree []S) { tree = make([]S, 0) points := make([]*S, 0) for index := 0; index <= 5; index++ { tree = append(tree, S{ Data: index, Children: make([]S, 0), }) s := tree[index] //标记1 points = append(points, &s) } //标记2 //for index := range tree { // points = append(points, &(tree[index])) //} for index := range tree { // 区别在这里 tree[index].Children = append(tree[index].Children,S{ Data: tree[index].Data * 10, Children: make([]S, 0), }) } return } ``` 输出结果 ```shell []main.S{main.S{Data:0, Children:[]main.S{main.S{Data:0, Children:[]main.S{}}}}, main.S{Data:1, Children:[]main.S{main.S{Data:10, Children:[]main.S{}}}}, main.S{Data:2, Children:[]main.S{main.S{Data:20, Children:[]main.S{}}}}, main.S{Data:3, Children:[]main.S{main.S{Data:30, Children:[]main.S{}}}}, main.S{Data:4, Children:[]main.S{main.S{Data:40, Children:[]main.S{}}}}, main.S{Data:5, Children:[]main.S{main.S{Data:50, Children:[]main.S{}}}}} ``` 你的标记1无效 标记2有效 是因为你在标记2中再次使用了返回值tree, 阻止了golang的编译器过早把tree优化到返回栈里. 标记1使用过tree之后后面没有再次使用, golang会认为tree的值不会改变了 所以会出现你发现的这个奇怪的问题. 而且你这个程序本身思路也比较奇葩, point压根就没啥用处...
#1
非常感谢解答! 1. 按照优化的思路来说,似乎标记1和标记2还是应该等价的? 至少在标记2 之后也没有再次用到tree,当然了,优化这种玄学也不排除2可以但是1不行的情况,确实是个思路 2.这个问题来源于我司的业务代码,提问不能放实际代码(太长了主要)这段代码主要意在提炼问题本质而不是讨论代码合理性,所以修改后的代码没有参考意义,这里实际上还是讨论 “为什么指针地址一样但是修改不了” 的问题。 3.在问题的`30`行的 `for`之前,我检查过两种方式,`points` 和 `tree` 的地址是一一对应的,也就是说后续的 `points` 操作的地址仍然是 `tree` 的地址,莫非优化之后,赋值就失败了吗? 最后还是再次感谢提供了新的思路
#2