我有一个结构:
type user struct { Id string .. data_ptr *userData }
我在全球范围内存储一部分用户:
type Hall struct { users []user } var hall = Hall{} //global
最后,http处理程序:
func dataHandler(response http.ResponseWriter, request *http.Request) { userExist, user_ptr := hall.haveUserId() //works fine switch requestType { case "load": user_ptr.loadData() //data loaded and user_ptr.data_ptr is set case "newData": user_ptr.data_ptr = newData // <-- this is it, now previously set data_ptr == nil
所以,为什么会这样,我的意思是我发送“加载”请求,它加载数据,设置data_ptr为user_ptr。但是在下一次调用“ newData”请求时,user_ptr.data_ptr是nil?
data_ptr
user_ptr
user_ptr.data_ptr
nil
以防万一,这里是loadData():
loadData()
func (p *user) loadData(userId) { .. data := userData {} p.data_ptr = &data }
编辑: 哪里user_ptr来的:
func (h *Hall) haveUserId(id string) (bool, *user) { for _, u := range h.users { if u.Id == id { fmt.Println("UID found") return true, &u } } return false, nil }
这是因为您对 副本 进行操作,而不是对slice元素本身进行操作。
在haveUserId()函数中for ... range,make循环遍历的元素的副本,然后返回此副本的地址。因此,稍后您将修改此副本,该副本与切片中的值无关。因此,如果稍后您检查slice元素中的地址,则该地址仍将保持不变(nil)。
haveUserId()
for ... range
可能的解决方法:返回slice元素的地址: &h.users[i]
&h.users[i]
func (h *Hall) haveUserId(id string) (bool, *user) { for i := range h.users { if h.users[i].Id == id { fmt.Println("UID found") return true, &h.users[i] } } return false, nil }
为了说明这一点,请参见以下示例:
type Point struct{ x, y int } ps := []Point{{1, 2}, {3, 4}} fmt.Println(ps) // Output: [{1 2} {3 4}] for _, v := range ps { v.x += 10 // Modifies just the copy } fmt.Println(ps) // Output (unchanged): [{1 2} {3 4}] for i := range ps { ps[i].x += 10 // Modifies value in slice } fmt.Println(ps) // Output (changed): [{11 2} {13 4}]
在Go Playground上尝试一下。