无效的内存地址或切片上的空指针解引用

huangapple go评论68阅读模式
英文:

Invalid memory address or nil pointer dereference on slice

问题

为什么在运行时 greets 给我返回 invalid memory address or nil pointer dereference 错误?

type Response struct {
  Message string `json:"message"`
}

type ResponseList struct {
  Items []*Response `json:"items"`
}

func (gs *GreetingService) List(r *http.Request, req *Request, resp *ResponseList) error {
  greets := make([]*Response, 2, 2)
  greets[0].Message = "hello"
  greets[1].Message = "goodbye"
  resp.Items = greets
  return nil
}

在这段代码中,greets 是一个指向 Response 结构体的切片。在创建 greets 切片时,你指定了它的长度和容量都为 2。然而,在给 greets 中的元素赋值时,你没有为每个元素分配内存空间,导致出现了空指针解引用的错误。

要解决这个问题,你需要为 greets 中的每个元素分配内存空间。可以通过使用 new 关键字或者直接创建 Response 结构体的实例来完成。以下是修复后的代码示例:

func (gs *GreetingService) List(r *http.Request, req *Request, resp *ResponseList) error {
  greets := make([]*Response, 2, 2)
  greets[0] = &Response{Message: "hello"}
  greets[1] = &Response{Message: "goodbye"}
  resp.Items = greets
  return nil
}

修复后的代码会为 greets 中的每个元素分配内存空间,并将相应的消息赋值给它们。这样就可以避免空指针解引用错误的发生。

英文:

Why does greets give me invalid memory address or nil pointer dereference when running?

type Response struct {
  Message string `json:"message"`
}

type ResponseList struct {
  Items []*Response `json:"items"`
}

func (gs *GreetingService) List(r *http.Request, req *Request, resp *ResponseList) error {
  greets := make([]*Response,2,2)
  greets[0].Message="hello"
  greets[1].Message="goodbye"
  resp.Items = greets
  return nil
}

答案1

得分: 8

你没有分配 Response 对象,只是分配了指针。指针被初始化为 nil。

你可以这样说 greets[0] := &Response{Message: "hello"}。或者,更好的方式是,从一个空切片开始,然后使用 append 添加任意数量的 *Response

greets := []*Response{} // 或者 ResponseList{}
greets = append(greets, &Response{Message: "hello"})
greets = append(greets, &Response{Message: "goodbye"})

编辑: 注意 Anonymous 的替代方法:如果你知道 Response 的数量,你可以使用字面量来设置整个结构,例如 resp.Items = {{Message: "hello"}}。即使 Response 是一个指针,也可以工作,并且不需要在每个 Response 上显式指定类型名称。非常酷。

英文:

You haven't allocated the Response objects, just pointers. Pointers are inited to nil.

You could say greets[0] := &Response{Message: "hello"}. Or, perhaps better, start with an empty slice and append as many *Responses as you want:

greets := []*Response{} // or ResponseList{}
greets = append(greets, &Response{Message: "hello"})
greets = append(greets, &Response{Message: "goodbye"})

Edit: Note Anonymous's alternative: you can use a literal to set up the whole structure if you know the number of Responses, as in resp.Items = {{Message: "hello"}}. Works even though Response is a pointer, and works without an explicit type name on each Response. Very cool.

答案2

得分: 2

在Go语言中,对切片和结构体字面量的支持可以帮助你避免样板代码,并确保你的代码正确无误。

以下是使用切片字面量编写List方法的示例代码:

func (gs *GreetingService) List(r *http.Request, req *Request, resp *ResponseList) error {
    resp.Items = []*Response{
        {Message: "hello"},
        {Message: "goodbye"},
    }
    return nil
}

这段代码使用切片字面量为resp.Items赋值,其中包含了两个Response结构体字面量。

英文:

The support for slice and struct literals in Go can help you avoid the boilerplate as well as get your code right.

Here's how to write your List method using a slice literal.

func (gs *GreetingService) List(r *http.Request, req *Request, resp *ResponseList) error {
    resp.Items = []*Response{
		{Message: "hello"},
		{Message: "goodbye"},
    }
    return nil
}

huangapple
  • 本文由 发表于 2013年12月24日 10:03:33
  • 转载请务必保留本文链接:https://go.coder-hub.com/20753884.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定