前言
golang空结构体有零内存占用、地址相同、无状态的特性,接下来我们将逐一探讨空结构体的特性以及该特性用于特定场景中对开发效率的提高
提示:以下是本篇文章正文内容,下面案例可供参考
一、空结构体的特性
零内存占用
空结构体不占用任何内存空间,该特性使得空结构体在内存优化方面非常有用。我们创建一个数据类型(int、string、struct),然后通过sizeof函数计算每个数据类型占用的空间大小(8,16,0)
下面展示一些 内联代码片
。
// 零内存
func TestSize() {
var a int
var b string
var c struct{}
fmt.Println(unsafe.Sizeof(a))
fmt.Println(unsafe.Sizeof(b))
fmt.Println(unsafe.Sizeof(c))
}
运行结果:
地址相同
无论你创建多少个空结构体,他们指向的地址都是相同的
// 地址相同
func TestAddress(){
var e1 struct{}
var e2 struct{}
fmt.Printf("address of e1: %p\n", &e1)
fmt.Printf("address of e2: %p\n", &e2)
fmt.Println(&e1==&e2)
}
运行结果:
无状态
由于空结构体不含有任何字段,因此他不能有状态。使得空结构体在表示无状态的对象或情况时非常有用
二、空结构体的应用场景
实现Set集合类型
golang中没有内置set数据类型,我们可以结合map、空结构体的特性来实现一个set集合数据类型
map的key具有唯一性,空结构体具有零内存的特性,所以可以设置map的key为具体的数据类型,value统一为空结构体(map[K]struct{})
// 实现set集合类型
// 泛性map
type Set[K comparable] map[K]struct{}
func (s Set[K]) Add(val K){
s[val]=struct{}{}
}
func (s Set[K]) Remove(val K){
delete(s, val)
}
func (s Set[K]) Contains(val K) bool{
_,ok:=s[val]
return ok
}
func set_operation(){
set:=Set[string]{}
set.Add("bob")
fmt.Println(set.Contains("bob"))
set.Remove("bob")
fmt.Println(set.Contains("bob"))
}
用于通道信号
空结构体用于Goroutine之间的信号传递,尤其是不关心通道中传递的具体数据的场景下。我们仅仅需要一个触发信号,我们可以使用空结构体的零内存特性,减少信号传递过程中的内存开销
// 作为通道信号
func chan_operation(){
quit:=make(chan struct{})
go func(){
fmt.Println("工作中")
time.Sleep(3*time.Second)
close(quit)
}()
<-quit
fmt.Println("已收到退出信号,退出中")
}
作为方法接收器
有时候我们需要创建一组方法集的实现(一般来说是实现一个接口),但并不需要在这个实现中存储任何数据,这种情况下,我们可以使用空结构体来实现:
// 作为方法接收器
type Person interface{
SayHello()
Sleep()
}
type CMY struct{}
func (c CMY) SayHello(){
fmt.Println("saying hello")
}
func (c CMY) Sleep(){
fmt.Println("sleeping")
}
func method_operation(){
var c CMY
c.SayHello()
c.Sleep()
}
总结
golang空结构体有零内存占用、地址相同、无状态的特性,接下来我们将逐一探讨空结构体的特性以及该特性用于特定场景中对开发效率的提高。后续将从源码的角度对空结构体进行分析