英文:
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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论