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

Den*_*s S 2 struct pointers go

我有一个结构:

type user struct {
Id string
..
data_ptr *userData
}
Run Code Online (Sandbox Code Playgroud)

我将用户切片存储在全局范围内:

type Hall struct {
    users []user
}

var hall = Hall{}    //global
Run Code Online (Sandbox Code Playgroud)

最后,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
Run Code Online (Sandbox Code Playgroud)

那么,到底为什么,我的意思是我发送“加载”请求,它加载数据,设置data_ptruser_ptr. 但是在下一次调用“newData”请求时,user_ptr.data_ptrnil

以防万一,这里是loadData()

func (p *user) loadData(userId) {
    ..
    data := userData {}
    p.data_ptr = &data
}
Run Code Online (Sandbox Code Playgroud)

编辑:其中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
}
Run Code Online (Sandbox Code Playgroud)

icz*_*cza 5

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

在您的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
}
Run Code Online (Sandbox Code Playgroud)

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

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}]
Run Code Online (Sandbox Code Playgroud)

Go Playground上试一试。