空结构体指的是不包含任何字段或元素的结构体,size 为 0
为什么要用空结构体:
空结构体 struct{ } 为什么会存在的核心理由就是为了节省内存。当你需要一个结构体,但是却丝毫不关系里面的内容,那么就可以考虑空结构体。golang 核心的几个复合结构 map ,chan ,slice 都能结合 struct{} 使用。
做控制而非数据信息: chan struct{}
实现set: map[string]struct{}
使用的场景主要分为三块:
1.实现方法接收者
2.实现集合类型
3.实现空通道
1、实现方法接收者
在业务场景下,我们需要将方法组合起来,代表其是一个 ”分组“ 的,便于后续拓展和维护。
但是如果我们使用:
type T struct{}
type T string
func (s *T) Call()
又似乎有点不大友好,因为作为一个字符串类型,其本身会占据定的空间。
这种时候我们会采用空结构体的方式,这样也便于未来针对该类型进行公共字段等的增加。
如下:
type T struct{}
func (s *T) Call() {
fmt.Println("脑子进煎鱼了")
}
func main() {
var s T
s.Call()
}
在该场景下,使用空结构体从多维度来考量是最合适的,易拓展,省空间,最结构化。
另外你会发现,其实你在日常开发中下意识就已经这么做了,你可以理解为设计模式和日常生活相结合的另类案例。
2、实现集合类型
在 Go 语言的标准库中并没有提供集合(Set)的相关实现,因此一般在代码中我们图方便,会直接用 map 来替代。
但有个问题,就是集合类型的使用,只需要用到 key(键),不需要 value(值)。
type Set map[string]struct{}
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("大鱼")
set.Append("小鱼")
set.Append("咸鱼")
set.Remove("咸鱼")
fmt.Println(set.Exist("死鱼"))
}
3、 实现空通道
在 Go channel 的使用场景中,常常会遇到通知型 channel,其不需要发送任何数据,只是用于协调 Goroutine 的运行,用于流转各类状态或是控制并发情况。
如下:
ch := make(chan struct{})
func main() {
ch := make(chan struct{})
go func() {
time.Sleep(1 * time.Second)
close(ch)
}()
fmt.Println("今天天气...")
<-ch
fmt.Println("很不错!")
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。