Go 空结构体 struct{} 的使用

Go 空结构体 struct{} 的使用

struct是Go中的关键字,用于定义结构类型。
例如:

type User struct {
    Name string
    Age  int
}

struct {}

struct {}是一个无元素的结构体类型,通常在没有信息存储时使用。优点是大小为0,不需要内存来存储struct {}类型的值。

struct {} {}

struct {} {}是一个复合字面量,它构造了一个struct {}类型的值,该值也是空。

go中可以使用 unsafe.Sizeof 计算出一个数据类型实例需要占用的字节数。我们验证一下:

package main

import (
    "fmt"
    "unsafe"
)

func main() {
    fmt.Println(unsafe.Sizeof(struct{}{})) 
}
E:\go\src\learngolang\emptyStruct>go run main.go
0

也就是说空结构体实例不占用任何内存空间。

空结构体的作用

1. 实现集合set

Go 语言标准库没有提供 Set 的实现,通常使用 map 来代替。事实上,对于集合来说,只需要 map 的键,而不需要值。

声明为声明为map[string]struct{},由于struct{}是空,不关心内容,这样map便改造为set 。

map可以通过“comma ok”机制来获取该key是否存在,例如_, ok := map["key"],如果没有对应的值,ok为false。可以通过定义成map[string]struct{}的形式,值不再占用内存。其值仅有两种状态,有或无。如果定义的是map[string]bool,则结果有true、false或没有三种状态,而且即使是将值设置为 bool 类型,也会多占据 1 个字节。因此呢,将 map 作为集合(Set)使用时,可以将值类型定义为空结构体,仅作为占位符使用即可。

type Set map[string]struct{}

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

func (s Set) Add(key string) {
    s[key] = struct{}{}
}

func (s Set) Delete(key string) {
    delete(s, key)
}

func main() {
    s := make(Set)
    s.Add("Tom")
    s.Add("Sam")
    fmt.Println(s.Has("Tom"))
    fmt.Println(s.Has("Jack"))
}

2 不发送数据的信道(channel)

基于channels发送消息有两个重要方面:发了消息、发了什么消息。一个强调了通讯的发生,一个强调了通讯的内容。当我们更希望强调通讯发生的时刻时,我们将它称为消息事件。有些消息事件并不携带额外的信息,它仅仅是用作两个goroutine之间的同步,这时候我们可以用struct{}空结构体作为channels元素的类型。用来通知子协程(goroutine)执行任务,或只用来控制协程并发度。

3 仅包含方法的结构体

在部分场景下,结构体只包含方法,不包含任何的字段。这时候我们就可以使用空结构体。

type calculateInt struct{} 

func (c calculateInt) add(x,y int) int {
    return x+y
}
func (c calculateInt) sub(x,y int) int {
    return x-y
}

其实,上面的calculateInt 可以是任何类型,如type calculateInt bool,但是struct{}不占用任何空间,逻辑上也更合理,因此还是它最好。

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容