为了账号安全,请及时绑定邮箱和手机立即绑定

分配的指针字段变为 <nil>

分配的指针字段变为 <nil>

Go
长风秋雁 2021-12-07 10:15:12
我有一个结构: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?以防万一,这里是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}
查看完整描述

1 回答

?
慕容3067478

TA贡献1773条经验 获得超3个赞

这是因为您操作的是副本而不是切片元素本身。


在您的haveUserId()函数中,它for ... range会复制它循环的元素,然后返回该副本的地址。稍后您将修改此副本,该副本与切片中的值无关。因此,如果稍后您检查切片元素中的地址,它仍然会保持不变(nil)。


可能的解决方法:返回切片元素的地址: &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}]


查看完整回答
反对 回复 2021-12-07
  • 1 回答
  • 0 关注
  • 132 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信