今天说一个小编本人真实经历过的一个面试题目吧。大概是2020年的7月份,是鹅厂的一个面试官问小编的,当场就懵了。小编当时面试的是一个Golang开发岗。题目是: 在Golang中空struct有什么用 。当时小编就蒙了,面试官告诉小编是 主要是做占位符,因为空struct占用的内存是0 。今天小编就和大家好好掰扯掰扯空struct的用法。
首先需要肯定的是面试官的说法,陈述了两个事实。下面我们一一说明。
1,空struct的占用空间为0。
2,空struct主要用作占位符。
空struct占用空间大小
前面呢只是小编说,占用空间为0,有道是耳听为虚,眼见为实,接下来给大家演示一下。在 Golang中,我们可以直接调用 unsafe.Sizeof 计算出一个数据类型占用的字节数。根据下面的结果,显而易见空struct实例不占据任何的内存空间。
package main
import (
"fmt"
"unsafe"
)
func main() {
struc := unsafe.Sizeof(struct{}{})
fmt.Println("空struct的大小为:", struc)
}
空struct的使用场景
空struct的使用的使用场景其实有很多,但是核心只有两点, 作为占位符和不占用内存空间 。
场景1:实现set
先给各位看官大人说一个简单的场景。比如说小编现在要给所有的粉丝朋友们发money,但是每个用户只能发一次,此时我们就需要记录一下那些用户发放过了。聪明的同学很快就能想到一种常见的数据结构了,譬如说Redis中的Set结构。那么问题来了,我们如果不借用数据库,简单地使用代码能实现吗。答案是肯定的,接下来小编就来给大家演示一下。
我们需要知道的是,实现一个自己的set,最简单的方法就是借用map了。那么小编给大家演示一下使用空struct方法。
package main
import (
"fmt"
"unsafe"
)
type Set map[string]struct{}
func (s Set) Get(key string) bool {
_, ok := s[key]
return ok
}
func (s Set) Add(key string) {
s[key] = struct{}{}
}
func (s Set) Del(key string) {
delete(s, key)
}
func main() {
set := make(Set)
set.Add("不穿格子衫的程序猿1")
set.Add("不穿格子衫的程序猿2")
set.Add("不穿格子衫的程序猿3")
fmt.Println(set.Get("不穿格子衫的程序猿1"))
fmt.Println(set.Get("不穿格子衫的程序猿2"))
fmt.Println("Set的大小为:", unsafe.Sizeof(set))
}
试想一下,用map实现set的时候value值是没有意义的,此时不管使用什么类型,都会占用一定的空间,即使是将值设置为 bool 类型,也会多占1个字节,那假设map中有一百万条数据,就会浪费1MB 的空间。但是使用空struct就不一样了。
场景2:作为无语义信号量
有时候我们使用channel时不需要传递任何数据,只需要通知其他goroutine执行任务即可。比如定时脚本之类的,此时使用空struct作为占位符就很合适了。
package main
import (
"fmt"
"time"
)
func worker(ch chan struct{}) {
<-ch
fmt.Println("更多免费资料,关注公众号:不穿格子衫的程序猿。")
close(ch)
}
func main() {
ch := make(chan struct{})
go worker(ch)
ch <- struct{}{}
// 防止主线程提前退出
time.Sleep(1 * time.Second)
}
其实从理论上讲,还可以有很多种应用方式,只不过那些场景不太常见而已,小编此处就不一一列举了。另外空struct对于Golang的内存对齐也有一定的影响,后续小编会针对这个知识点做详细的解说。
福利赠送
又到了大家期待的福利时间了。本次赠送的是Golang必读书籍50本。
废话不多说,各位看官大人要怎么获取呢。很简单, 关注小编,私信 「 资料 」即可获得免费获取方式。
如果大家有比较好的资源欢迎相互交流,共同提高。同时有部分素材来源于网络,如侵,联删 。