分配的指针字段变为< nil> [英] Assigned pointer field becomes <nil>

查看:85
本文介绍了分配的指针字段变为< nil>的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个struct:

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

我在全局范围内存储一部分用户:

 类型Hall结构{
用户[]用户
}

var hall = Hall {} // global

最后,http处理程序:

  func dataHandler(response http.ResponseWriter,request * http.Request){
userExist,user_ptr:= hall.haveUserId()//正常工作
switch requestType {
caseload:
user_ptr.loadData()//数据加载并设置user_ptr.data_ptr
casenewData:
user_ptr.data_ptr = newData //< - 就是这样,现在已经设置data_ptr == nil

heck,我的意思是我发送加载请求,它加载数据,为 user_ptr 设置 data_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:=范围h.users {
如果u.Id == id {
fmt.Println(找到UID)
返回true,&
}
}
return false,nil
}


解决方案



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

可能fix:返回slice元素的地址:& 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
}

为了说明这一点,请看这个例子:

 类型Point结构{x,y int} 
ps:= [] Point {{1,2},{3,4}}
fmt.Println(ps)//输出:[{1 2} {3 4}]

for _,v:=范围ps {
vx + = 10 //仅修改副本
}
fmt.Println(ps)//输出(不变):[{1 2} {3 4}]

for i:= range ps {
ps [i] .x + = 10 //修改切片中的值
}
fmt.Println(ps)//输出(改变):[{11 2} {1 3 4}]

试试 Go Goground


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
}

解决方案

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.

这篇关于分配的指针字段变为&lt; nil&gt;的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆