1.go语言中的空结构体初探

72 阅读1分钟

普通变量

在go中通过unsafe.Sizeof可以获取go某种类型的字节数,有些类型是跟随系统的字长的,比如int、指针这些类型。

通过程序可以打印:

func TestVariable(t *testing.T) {
	fmt.Printf("int size: %d\n", unsafe.Sizeof(int(0)))
	fmt.Printf("int32 size: %d\n", unsafe.Sizeof(int32(0)))
	fmt.Printf("int64 size: %d\n", unsafe.Sizeof(int64(0)))
	i := 7
	fmt.Printf("pointer size: %d\n", unsafe.Sizeof(&i))
	}
	
	//output:
int size: 8
int32 size: 4
int64 size: 8
pointer size: 8

空结构体

还有一种类型的大小是0,那就是空结构体。

如果大小是0字节,那么他有内存地址么?

答案是有的。

fmt.Printf("empty struct size: %d\n", unsafe.Sizeof(struct{}{}))
	s1 := emptyStruct{}
	s2 := emptyStruct{}
	fmt.Printf("empty struct addr: %p\n", &s1)
	fmt.Printf("empty struct addr: %p\n", &s2)
	
	//output
empty struct size: 0
empty struct addr: 0x69ec20
empty struct addr: 0x69ec20

而且空结构体,在独立使用的时候,他的内存地址是固定的,在go中叫zerobase。

runtime/malloc.go
// base address for all 0-byte allocations
var zerobase uintptr

如果是在其他结构体中使用,他的地址是跟随结构体的,可以看到是跟zerobase完全不一样的一段地址。

type embedStruct struct {
	field1 emptyStruct
	field2 int32
}

func TestVariable(t *testing.T) {
	s3 := embedStruct{}
	fmt.Printf("empty struct addr: %p\n", &s3.field1)

}

//output
empty struct addr: 0xc000012328

使用场景:

主要目的就是节约内存,具体的可以

  1. 结合map使用,用作set
  2. 结合channel使用,用于信号通知