如何避免“无效的内存地址或空指针引用”错误?

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

How does one avoid "invalid memory address or null pointer dereference" errors?

问题

我想知道如何结构化这个示例代码以避免空指针解引用恐慌:

package main

import "fmt"

type Astruct struct {
    Number int
    Letter string
}

type Bstruct struct {
    foo          int
    AStructList *[]Astruct
}

type Cstruct struct {
    Bstruct
}

func (a *Astruct) String() string {
    return fmt.Sprintf("Number = %d, Letter = %s", a.Number, a.Letter)
}

func main() {
    astructlist := make([]Astruct, 3) // line 1
    for i := range astructlist {      // line 2
        astructlist[i] = Astruct{i, "a"} // line 3
    }                                 // line 4
    c := new(Cstruct)
    c.Bstruct = Bstruct{100, &astructlist} // line 6

    for _, x := range *c.Bstruct.AStructList {
        fmt.Printf("%s\n", &x)
    }
}

如果我省略main()中的第1-4行和第6行,我会得到一个空指针解引用恐慌。除了检查c != nil之外,有没有办法避免这些恐慌?

提前感谢您的帮助!

英文:

I'm wondering how I can structure this example code to help avoid null pointer dereference panics:

package main

import "fmt"

type Astruct struct {
    Number int
    Letter string
}

type Bstruct struct {
    foo int
    AStructList *[]Astruct
}

type Cstruct struct {
    Bstruct
}

func (a *Astruct) String() string {
    return fmt.Sprintf("Number = %d, Letter = %s", a.Number, a.Letter)
}

func main() {
    astructlist := make([]Astruct, 3)      // line 1
    for i := range astructlist {           // line 2
    	astructlist[i] = Astruct{i, "a"}   // line 3
    }                                      // line 4
    c := new(Cstruct)
    c.Bstruct = Bstruct{100, &astructlist} // line 6

    for _, x := range(*c.Bstruct.AStructList) {
	    fmt.Printf("%s\n", &x)
    }
}

If I omit lines 1-4 and 6 of main(), I get a null pointer dereference panic. Short of checking if c != nil, is there a way to avoid these panics?

Thanks in advance for any help!

答案1

得分: 6

在这种特殊情况下,你可以使用惯用的Go语法。将AStructList *[]Astruct改为AStructList []*Astruct。例如,

package main

import "fmt"

type Astruct struct {
    Number int
    Letter string
}

type Bstruct struct {
    foo         int
    AStructList []*Astruct
}

type Cstruct struct {
    Bstruct
}

func (a *Astruct) String() string {
    return fmt.Sprintf("Number = %d, Letter = %s", a.Number, a.Letter)
}

func main() {
    astructlist := make([]*Astruct, 3)            // line 1
    for i := range astructlist {                  // line 2
        astructlist[i] = &Astruct{i, "a"}         // line 3 
    }                                             // line 4
    c := new(Cstruct)
    c.Bstruct = Bstruct{100, astructlist}         // line 6

    for _, x := range c.Bstruct.AStructList {
        fmt.Printf("%s\n", x)
    }
}

一般来说,你需要在使用指针之前要么给它赋一个非nil的值,要么在使用之前进行nil的检查。当你分配内存而没有显式初始化时,它会被设置为该类型的零值,对于指针来说,零值是nil

零值

当为存储值分配内存时,无论是通过声明还是通过调用make或new,如果没有提供显式的初始化,内存都会被赋予默认初始化。这样值的每个元素都会被设置为其类型的零值:布尔类型为false,整数类型为0,浮点数类型为0.0,字符串类型为"",指针、函数、接口、切片、通道和映射类型为nil。这种初始化是递归进行的,因此,如果没有指定值,结构体数组的每个元素的字段都会被置为零值。

英文:

In this particular case, you could use idiomatic Go. Change AStructList *[]Astruct to AStructList []*Astruct. For example,

package main

import "fmt"

type Astruct struct {
    Number int
    Letter string
}

type Bstruct struct {
    foo         int
    AStructList []*Astruct
}

type Cstruct struct {
    Bstruct
}

func (a *Astruct) String() string {
    return fmt.Sprintf("Number = %d, Letter = %s", a.Number, a.Letter)
}

func main() {
    astructlist := make([]*Astruct, 3)            // line 1
    for i := range astructlist {                  // line 2
        astructlist[i] = &Astruct{i, "a"}         // line 3 
    }                                             // line 4
    c := new(Cstruct)
    c.Bstruct = Bstruct{100, astructlist}         // line 6

    for _, x := range c.Bstruct.AStructList {
        fmt.Printf("%s\n", x)
    }
}

In general, it's your responsibility to either assign a non-nil value to a pointer or test for nil before its use. When you allocate memory without explicitly intializing it, it's set to the zero value for the type, which is nil for pointers.

> The zero value
>
> When memory is allocated to store a value, either through a
> declaration or a call of make or new, and no explicit initialization
> is provided, the memory is given a default initialization. Each
> element of such a value is set to the zero value for its type: false
> for booleans, 0 for integers, 0.0 for floats, "" for strings, and nil
> for pointers, functions, interfaces, slices, channels, and maps. This
> initialization is done recursively, so for instance each element of an
> array of structs will have its fields zeroed if no value is specified.

huangapple
  • 本文由 发表于 2012年2月27日 19:48:39
  • 转载请务必保留本文链接:https://go.coder-hub.com/9464516.html
匿名

发表评论

匿名网友

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

确定