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

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
", &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!

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
", 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.