分配的指针字段变为< nil> [英] Assigned pointer field becomes <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.
这篇关于分配的指针字段变为< nil>的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!