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