空结构体特殊性

func main() {
    var s struct{}
    fmt.Println(unsafe.Sizeof(s))
}

输出结果:

0

这是Go 编译器在内存分配时做的优化项

// base address for all 0-byte allocations
var zerobase uintptr

// Allocate an object of size bytes.
// Small objects are allocated from the per-P cache's free lists.
// Large objects (> 32 kB) are allocated straight from the heap.
func mallocgc(size uintptr, typ *_type, needzero bool) unsafe.Pointer {
 ...
 if size == 0 {
  return unsafe.Pointer(&zerobase)
 }
}

当发现 size 为 0 时,会直接返回变量 zerobase 的引用,该变量是所有 0 字节的基准地址,不占据任何宽度。

使用

  • 实现方法接收者
  • 实现集合类型
  • 实现空通道

实现方法接收者

type T struct{}

func (s *T) Call() {
}

实现集合类型

集合类型的使用,只需要用到 key(键),不需要 value(值)

type Set map[string]struct{}

func (s Set) Append(k string) {
 s[k] = struct{}{}
}

func (s Set) Remove(k string) {
 delete(s, k)
}

func (s Set) Exist(k string) bool {
 _, ok := s[k]
 return ok
}

func main() {
 set := Set{}
 set.Append("1")
 set.Append("2")
 set.Append("3")
 set.Remove("1")

 fmt.Println(set.Exist("1"))
}

空结构体作为占位符,不会额外增加不必要的内存开销

实现空通道

在 Go channel 的使用场景中,常常会遇到通知型 channel,其不需要发送任何数据,只是用于协调 Goroutine 的运行,用于流转各类状态或是控制并发情

func main() {
 ch := make(chan struct{})
 go func() {
  time.Sleep(1 * time.Second)
  close(ch)
 }()

 fmt.Println("1")
 <-ch
 fmt.Println("2")
}

由于该 channel 使用的是空结构体,因此也不会带来额外的内存开销

0条评论 顺序楼层
请先登录再回复