【发布时间】:2020-07-15 17:44:46
【问题描述】:
我正在尝试构建一个新的结构列表,其中包含对另一个切片中存在的项目的引用。看到了就更容易理解了,所以我准备了一个可以运行的sn-p。
我有一个包含两个点(笛卡尔坐标)的列表(dummylist),我想解析它以构建一个新列表(mylist),其中包含具有某些特征的项目(在示例中,X > 80)。我定义了两点:{X:90.0, Y:50.0} 和 {X:20.0 , Y:30.0}。我希望 mylist 将包含 {X:90.0, Y:50.0},而不是最后有 {X:20.0, Y:30.0}。通过到处打印,我可以验证算法是否正常工作(它在正确的情况下进入“if”条件),但最后,“mylist”包含错误的元素。
package main
import(
"fmt"
)
func main() {
type point struct {
X float64
Y float64
}
type pointsList []point
type pointContainer struct {
Point *point
}
type pointContainerList []pointContainer
// Prepare a slice with two elements
dummylist := new(pointsList)
*dummylist = append(*dummylist, point{X:90.0, Y:50.0})
*dummylist = append(*dummylist, point{X:20.0 , Y:30.0})
// My empty list
mylist := new(pointContainerList)
fmt.Println(fmt.Sprintf("---- At the beginning, mylist contains %d points", len(*mylist)))
// Filter the initial list to take only elements
for _, pt := range *dummylist {
fmt.Println("\n---- Evaluating point ", pt)
if pt.X > 80 {
fmt.Println("Appending", pt)
*mylist = append(*mylist, pointContainer{Point: &pt})
fmt.Println("Inserted point:", (*mylist)[0].Point, "len = ", len(*mylist))
}
}
// mylist should contain {X:90.0, Y:50.0}, instead...
fmt.Println(fmt.Sprintf("\n---- At the end, mylist contains %d points", len(*mylist)))
fmt.Println("Content of mylist:", (*mylist)[0].Point)
}
在这里你可以运行代码: https://play.golang.org/p/AvrC3JJBLdT
一些有用的考虑:
我已经通过多个测试看到,最后, mylist 包含循环中最后一个解析的项目。我觉得引用有问题。就像列表中插入的项目(在第一次迭代中)取决于其他迭代的“pt”。相反,如果我使用索引(for i, pt := range *dummylist 和 (*dummylist)[i]),一切正常。
在谈论 Golang 中的错误之前……我是否遗漏了什么?
【问题讨论】:
-
与此问题的问题原因相同:stackoverflow.com/questions/62910940/…(答案在评论中)
-
简而言之,
pt在每次迭代中重用,因此表达式&pt将 always 评估为相同的值,即相同的指针指向相同的内存地址,因此容器列表中的每个元素都是指向单个pt值的指针的副本,在循环结束时,它将始终包含最后一个元素切片/数组的迭代次数。 -
... 只需在迭代块的顶部执行
pt := pt即可解决您的问题。
标签: go