Golang里空结构体struct{}的介绍和使用

s t r u c t struct struct G o l a n g Golang Golang里的关键字,用于定义结构类型
比如

type Student struct{
	id int
	name string
}

struct{}是有 0 0 0个元素的结构体.
struct{}{}表示类型struct{}的值为空{}

1.性质

1.1不占用内存

大小为 0 0 0,不需要内存来存储struct{}类型的值。

func Test_Size(t *testing.T) {
	var x int
	var y string
	var z struct{}
	t.Log(unsafe.Sizeof(x), unsafe.Sizeof(y), unsafe.Sizeof(z)) //8 16 0
}

在这里插入图片描述

1.2 地址相同

定义两个struct{}类型的变量,打印并比较其地址,发现是相同的

func Test_Address(t *testing.T) {
	var x struct{}
	var y struct{}
	t.Logf("%p %p %v %v", &x, &y, &x == &y, x == y) // 0x1290460 0x1290460 true true
}

在这里插入图片描述

2.用途

2.1实现set

golang里没有实现set,如果在使用map的时候只关心key,不关心value的话,可以借助struct{}来实现set。比如key为string类型,那么set的实现map[string]struct{}。
因为struct{}不占用空间,所以在查找和判断的过程中速度会快,而且占用的内存也会小
简单实现:

func Test_set(t *testing.T) {
	set := make(map[string]struct{})
	set["a"] = struct{}{}
	if _, ok := set["a"]; ok {
		t.Log("exists") //exists
	}
}

在这里插入图片描述

使用interface{}实现

type Set map[interface{}]struct{}

func (s Set) Add(item interface{}) {
	s[item] = struct{}{}
}

func (s Set) Remove(item interface{}) {
	delete(s, item)
}

func (s Set) Contains(item interface{}) bool {
	_, exists := s[item]
	return exists
}

func Test_any_set(t *testing.T) {
	set := make(Set)

	set.Add("apple")
	set.Add("banana")
	set.Add("orange")

	fmt.Println("Set:", set)

	fmt.Println("Contains apple:", set.Contains("apple"))
	fmt.Println("Contains grape:", set.Contains("grape"))

	set.Remove("banana")

	fmt.Println("Set:", set)
}

在这里插入图片描述
使用泛型实现:

type Set[T comparable] map[T]struct{}

func (s Set[T]) Add(v T) {
	s[v] = struct{}{}
}

func (s Set[T]) Remove(v T) {
	delete(s, v)
}

func (s Set[T]) Contains(v T) bool {
	_, ok := s[v]
	return ok
}

func (s Set[T]) Len() int {
	return len(s)
}

func (s Set[T]) Values() []T {
	values := make([]T, 0, s.Len())
	for v := range s {
		values = append(values, v)
	}
	return values
}

func Test_any_set(t *testing.T) {
	s := Set[string]{}
	s.Add("apple")
	s.Add("banana")
	s.Add("orange")

	fmt.Println("Set:", s.Values())

	fmt.Println("Contains apple:", s.Contains("apple"))
	fmt.Println("Contains grape:", s.Contains("grape"))

	s.Remove("banana")

	fmt.Println("Set:", s.Values())
}

在这里插入图片描述

2.2. 用于无数据的channel

有的时候 c h a n n e l channel channel不需要发送数据,只需要一个触发信号,就可以使用struct{}来减少信号传递过程中的内存开销
a. 等待协程完成
w o r k e r worker worker函数是一个协程,它会模拟一些工作并在完成后发送空结构体值到 d o n e done done通道。
T e s t _ w a i t Test\_wait Test_wait函数中,我们通过从 d o n e done done通道接收空结构体值来等待工作完成。

func worker(done chan struct{}) {
	fmt.Println("Worker: Performing some work...")
	time.Sleep(2 * time.Second)
	fmt.Println("Worker: Work completed!")
	done <- struct{}{} // 发送空结构体值表示工作完成
}
func Test_wait(t *testing.T) {
	done := make(chan struct{})
	go worker(done)
	<-done // 接收空结构体值,等待工作完成
	t.Log("Main: Done!")
}

在这里插入图片描述

b.触发事件
w a i t F o r E v e n t waitForEvent waitForEvent函数会等待接收到空结构体值,表示事件发生。
t r i g g e r E v e n t triggerEvent triggerEvent函数会在一段时间后发送空结构体值到event通道,表示事件发生。
通过使用空结构体值作为通道元素,我们可以简单地实现事件的触发和等待。

func waitForEvent(event chan struct{}) {
	fmt.Println("Waiting for event...")
	<-event // 等待接收到空结构体值,表示事件发生
	fmt.Println("Event received!")
}

func triggerEvent(event chan struct{}) {
	time.Sleep(2 * time.Second)
	fmt.Println("Triggering event...")
	event <- struct{}{} // 发送空结构体值,表示事件发生
}
func Test_event(t *testing.T) {
	event := make(chan struct{})
	go waitForEvent(event)
	go triggerEvent(event)
	time.Sleep(3 * time.Second)
}

在这里插入图片描述

2.3 方法接收器

实现一个接口,只需要实现一些方法,不用声明一些额外的数据,可以用struct{}来实现,也可以换成其他任意的变量,比如 i n t int int b o o l bool bool

type Animal interface {
	Shouting()
}
type Dog struct{}

func (dog *Dog) Shouting() {
	fmt.Println("wang wang wang")
}
  • 31
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

豆沙睡不醒

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值