duane9322 2016-01-13 07:40
浏览 23
已采纳

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

I have a struct:

type user struct {
Id string
..
data_ptr *userData
}

And I store slice of users in global scope:

type Hall struct {
    users []user
}

var hall = Hall{}    //global

Finally, http handler:

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

So, why the heck, I mean I send "load" request, it loads data, sets data_ptr for user_ptr. But on next call, "newData" request, user_ptr.data_ptr is nil?

Just in case, here is loadData():

func (p *user) loadData(userId) {
    ..
    data := userData {}
    p.data_ptr = &data
}

EDIT: where user_ptr comes from:

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条回答 默认 最新

  • duanjuan3931 2016-01-13 08:04
    关注

    This is because you operate on a copy and not on the slice element itself.

    In your haveUserId() function the for ... range makes a copy of the elements it loops over, and you return the address of this copy. And so later you will modify this copy which is independent from the value in the slice. So if later you check the address in the slice element, it will still be unchanged (nil).

    Possible fix: return the address of the slice element: &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
    }
    

    To demonstrate this, see this example:

    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}]
    

    Try it on the Go Playground.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 ansys fluent计算闪退
  • ¥15 有关wireshark抓包的问题
  • ¥15 需要写计算过程,不要写代码,求解答,数据都在图上
  • ¥15 向数据表用newid方式插入GUID问题
  • ¥15 multisim电路设计
  • ¥20 用keil,写代码解决两个问题,用库函数
  • ¥50 ID中开关量采样信号通道、以及程序流程的设计
  • ¥15 U-Mamba/nnunetv2固定随机数种子
  • ¥15 vba使用jmail发送邮件正文里面怎么加图片
  • ¥15 vb6.0如何向数据库中添加自动生成的字段数据。