【问题标题】:Assigned pointer field becomes <nil>分配的指针字段变为 <nil>
【发布时间】:2016-04-18 02:07:33
【问题描述】:

我有一个结构:

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_ptrnil

以防万一,这里是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
}

【问题讨论】:

  • 很可能是因为您操作的是 copy 而不是 slice 元素。你如何创建user_ptr
  • 能否请gofmt 显示您的实际代码,即user_ptr 的来源?
  • @icza 已更新,请参阅问题末尾的编辑
  • @user3591723,用相关文章更新问题
  • @DensiTensy 你没有添加足够的相关信息,仍然没有gofmt。只需显示您的整个 dataHandler 函数,因为它实际上是在您的代码中编写的。这不可能;到处都会有编译错误。

标签: pointers struct go


【解决方案1】:

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

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

可能的修复:返回切片元素的地址:&amp;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 上试用。

【讨论】:

  • 非常感谢,我从来没有猜到这个 range 行为差异
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-01-02
  • 2011-07-23
  • 1970-01-01
  • 1970-01-01
  • 2016-08-30
  • 2018-08-04
  • 2021-02-10
相关资源
最近更新 更多