Pointers 在循环中重置指针
这个问题暴露了我对Golang指针(或任何指针,真的)的基本理解不足,所以请容忍我。如果有帮助的话,我也在围棋场上举了一个类似的工作示例: 假设我有两个结构的基本父/子关系:Pointers 在循环中重置指针,pointers,go,Pointers,Go,这个问题暴露了我对Golang指针(或任何指针,真的)的基本理解不足,所以请容忍我。如果有帮助的话,我也在围棋场上举了一个类似的工作示例: 假设我有两个结构的基本父/子关系: //Parent type User struct{ ID int Rsvps []*Rsvp } //Child type Rsvp struct{ Response string } 在某种程度上,会创建一组用户和RSVP,并将信息存储在数据库中。在某个时刻,从数据库中提取信息并将
//Parent
type User struct{
ID int
Rsvps []*Rsvp
}
//Child
type Rsvp struct{
Response string
}
在某种程度上,会创建一组用户和RSVP,并将信息存储在数据库中。在某个时刻,从数据库中提取信息并将其写回这些结构中的时候到了。当使用关系数据库时,我通常会尝试使用一个查询来完成它,这种模式我已经使用了很多年,但可能不再是正确的方式。我将设置一个循环来提取数据。下面是一些带有许多注释的伪代码:
func getUsersAndRsvps() []*User{
sql := "SELECT * FROM users LEFT JOIN rsvps ON users.field1 = rsvps.field1 ORDER BY user.ID;"
dataset := getDataset(sql)
result = []*User{}
rsvps = []*Rsvp{}
//Oh, but you already see the problem here, don't you! I'm defining
//rsvps outside of the loop, and the values contained at its address
//will become values for all users, instead of per user. Yet, how
//else can I collect together rsvps while iterating?
user = User{} //hold onto a user while iterating
lastUserID := int64(0) //track when we move from one user to the next
for _, record := range dataset{
thisUserID := record.ID
//When this user is different from last user
//take the collected rsvps and write them into
//the (old) user, then continue iterating...
if lastUserID != thisUserID && lastUserID > 0{
//So, right here is the big problem. I'm writing
//the address of collected rsvps into the previous user record.
//However, on each iteration, that address gets all
//new info, such that at the end of the readout,
//all users have the same rsvps.
user.Rsvps = rsvps
result = append(result, &user)
//So, yes, I "blank out" the rsvps, but that only goes
//to make the last user's rsvps be those shared among all
rsvps = []*Rsvp{}
}
//Gather rsvps
rsvp = getRsvp(rsvp) //defined elsewhere
rsvps = append(rsvps, &rsvp)
user = getUser(record) //defined elsewhere
lastUserID := thisUserID
}
//Capture last record
user.Rsvps = rsvps
result = append(result, &user)
}
为了使问题简洁明了,我应该如何迭代一个数据集,将项目收集到一个片段中,然后将该片段写入一个唯一的内存点,以便下一组迭代不会覆盖它?如何执行以下操作:
package main
import (
"fmt"
)
type User struct {
ID int
Rsvps []*Rsvp
}
type Rsvp struct {
Response string
}
func main() {
users := []int{1, 2, 3}
responses := []string{"Yes", "No", "Maybe"}
var results []*User
for _, i := range users {
r := Rsvp{Response: responses[i-1]} // create new variable
u := User{ID: i}
u.Rsvps = append(u.Rsvps, &r)
results = append(results, &u)
}
for _, r := range results {
fmt.Println(r.ID, r.Rsvps[0].Response)
}
}
我以您的游乐场为例,删除注释并更改代码以获得所需的输出。主要的变化是我不再重复使用
r
。最初您总是附加&r
,但在循环开始时更改r
。当然,这会改变r指向的内存,使所有内容都成为可能问题不是由指向Rsvp
的指针引起的,而是以下语句:
在每次迭代过程中,变量user
的值被覆盖,但由于变量user
是在循环外部定义的,因此变量user
(即&user
)的地址将保持不变。因此,结果
切片中的元素将是相同的,即单个用户的地址
变量,其中的值是从最后一条记录中捕获的。将append
语句更改为:
//result = append(result, &user)
u := user
result = append(result, &u)
可以在以下位置找到演示此问题的最低示例。每个变量都会写入自己的内存。如果希望某个变量在循环的作用域(或任何块)之外持续存在,请在该块之外声明该变量。是。我想这就是我在做的,除非我误解了你的解决方案。我将指针切片变量设置在循环范围之外,只是为了观察它在每次迭代时被重写。哪个变量被重写了?我真的不知道您打算在这个示例中做什么。我建议停止尝试在作用域之间共享数据,并将其重构为一些返回您感兴趣的数据的函数。。。基于psuedocode,我认为它看起来基本正确,但它告诉我们的东西很少。如果你能发表一篇文章,我们可能会提供更多的见解。谢谢。在游乐场示例中,我没有捕捉到我试图为一个用户收集多个RSVP的问题。我需要一些方法在循环之前定义一个片段,然后在循环期间为一个用户收集所有RSVP,然后在循环遇到新用户时将收集的RSVP分配给用户。天哪,这是一个多么“简单”的答案。非常感谢。只需将变量设置为另一个“fresh”变量以保留它,然后将该变量附加到切片。明亮的与此同时,我刚刚准备了一份MCVE,以防有人(现在)对学术感兴趣:
//result = append(result, &user)
u := user
result = append(result, &u)