### 介紹 在平時做項目得時候,經常會看到很多包裡面定義了結構體。 e.g. 在`context`包裡面`Context`介面中的`Done()`方法,`Done()`返回一個是以空結構體定義數據的通道`chan struct{}`,那這裡他是有什麼特殊用意嗎?我們接下來分析`struct{}`的 ...
介紹
在平時做項目得時候,經常會看到很多包裡面定義了結構體。
e.g. 在context
包裡面Context
介面中的Done()
方法,Done()
返回一個是以空結構體定義數據的通道chan struct{}
,那這裡他是有什麼特殊用意嗎?我們接下來分析struct{}
的作用。
struct{}
空結構是沒有欄位的結構類型。下麵看示例:
type Demo struct{}
var demo struct{}
上面定義了一個Demo
的結構體,var 聲明變數demo
結構體。
width
在介紹空結構前,先來討論一下這個width
。
這裡說的這個“width”來自於 gc 編譯器
,它描述類型實例占用的存儲位元組數(一個位元組=8位
)。width
是類型的一個屬性。由於 Go
程式中的每個值都有一個類型,因此該值的width
由其類型定義,並且始終是 8 位的倍數
。
我們可以使用unsafe.Sizeof()
函數獲取任何值的width
:
var num int
var str string
fmt.Println(unsafe.Sizeof(num)) // output: 8
fmt.Println(unsafe.Sizeof(str)) // output: 16
數組類型的width
是其元素類型的倍數:
var arr [3]uint32
fmt.Println(unsafe.Sizeof(arr))
結構體提供了一種更靈活的方式來定義複合類型,其width
是組成類型的width
加上填充的總和:
type Test struct {
num16 uint16
num32 uint32
}
var test Test
fmt.Println(unsafe.Sizeof(test)) // 列印 8,而不是 6
列印結果是8
,這個就和記憶體對齊有關係了,這裡不作詳細的說明。
struct{}:
空結構體的位元組占用是多少呢,通過下麵的例子列印得到結果:
var s struct{}
fmt.Println(unsafe.Sizeof(s)) // 列印 0
由於空結構體占用 零位元組
,因此它不需要任何的填充。所以,struct{}
空結構組成的結構也不會占用任何存儲空間。
type S struct {
A struct{}
B struct{}
}
var s S
fmt.Println(unsafe.Sizeof(s)) // 列印 0
使用場景
- 可以聲明一個數組structs{},它們當然也是一樣不會占用存儲空間。
var arr [100000]struct{}
fmt.Println(unsafe.Sizeof(arr)) // 列印 0
- struct{}類型的
切片
只會占用其SliceHeader
的空間:
var arr = make([]struct{}, 1000000000)
fmt.Println(unsafe.Sizeof(arr)) // 列印 24
但是我們任然可以對這個切片正常操作:
var x = make([]struct{}, 100)
var y = x[:50]
fmt.Println(len(y), cap(y)) // 列印 50 100
- struct{}是可定址時,也一樣可以獲取它的地址:
var test struct{}
var data = &test
當兩個不同變數相同數據類型的時候,他們兩個的地址是等的:
var a, b struct{}
fmt.Println(&a == &b) // true
但是下麵兩個變數是不一樣的:
a := make([]struct{}, 10)
b := make([]struct{}, 20)
fmt.Println(&a == &b) // false, a 和 b 是不同的切片
fmt.Println(&a[0] == &b[0]) // true,它們的支持數組是相同的
總結
所以通過上面的分析,空結構體在記憶體上不占用資源,因此,我們在開發的時候可以通過chan struct{}
來實現 go 協程之間信號的傳遞等用途。
轉載:風向閱讀 - Golang空結構體struct{}的作用?
地址:https://www.aiweimeng.top/archives/42.html