Go 中 struct 初始化

Go 中 struct 初始化

刚接触的 Golang 总是被 Golang 当中的 struct 困扰,无论是初始化方式、多种数据类型和结构体组合方式,都和以往接触的其他语言有不小的区别,本文将进行梳理。

疑问

Go 当中有多种方式来初始化一个 struct:

  1. 初始化为值:foo:=Foo{},也可以通过默认方式来创建 var foo Foo
  2. 初始化为指针:foo:=New(Foo),当然也可以先初始化为值再取地址 foo:=&Foo{}

Go 当中存在多种类型,包括以下:

  1. 字面量值/指针:数值、字符串、布尔、数组
  2. 结构体值/指针
  3. slice、map、channel(需要make初始化的值)
  4. 还有就是 Go struct 特有的组合模式,其中就包含了内嵌值与内嵌指针的区别

定义如下的 Foobar 结构体:

实验

对于不同的 fb 分别运行以下代码,并观察结果:

go

1. fb := Foobar{}
2. fb := new(Foobar)
3. var fb Foobar
4. var fb *Foobar

func test(fb) {
	fmt.Printf("%+v\n", fb)
  fmt.Printf("slice is nil: %t\n", fb.s == nil)
	fmt.Printf("map is nil: %t\n", fb.m == nil)
	fmt.Printf("chan is nil: %t\n", fb.c == nil)

	fb.callPFoo()
	fb.callVFoo()
	fb.callPBar()
	fb.callVBar()
}

plain text

运行结果1:
{Foo:{} Bar:<nil> vFoo:{} pFoo:<nil> vNum:0 pNum:<nil> vArr:[0 0 0 0 0] pArr:<nil> s:[] m:map[] c:<nil>}
slice is nil: true
map is nil: true
chan is nil: true
pfoo
vfoo
pbar
panic: runtime error: invalid memory address or nil pointer dereference

plain text

运行结果2:
&{Foo:{} Bar:<nil> vFoo:{} pFoo:<nil> vNum:0 pNum:<nil> vArr:[0 0 0 0 0] pArr:<nil> s:[] m:map[] c:<nil>}
slice is nil: true
map is nil: true
chan is nil: true
pfoo
vfoo
pbar
panic: runtime error: invalid memory address or nil pointer dereference

plain text

运行结果3:
{Foo:{} Bar:<nil> vFoo:{} pFoo:<nil> vNum:0 pNum:<nil> vArr:[0 0 0 0 0] pArr:<nil> s:[] m:map[] c:<nil>}
slice is nil: true
map is nil: true
chan is nil: true
pfoo
vfoo
pbar
panic: runtime error: invalid memory address or nil pointer dereference

plain text

运行结果4:
<nil>
panic: runtime error: invalid memory address or nil pointer dereference

结论

  1. 对于前三种初始化方式,虽然可能获得了 struct value 或者 struct pointer,但是其最终指向的值内存都是相等的。唯独直接声明了 *struct 将无法初始化而获得 nil。
  2. 对于内嵌结构体,如果内嵌的为值,则可初始化;如果内嵌为指针,则无法初始化。
  3. slice、map、channel 等需要 make 的类型,都未被自动初始化。因为这三个类型本质上也是引用类型,需要引用一块未知大小的内存空间,故不直接进行初始化。