空結(jié)構(gòu)體struct{}解析

本篇文章轉(zhuǎn)自David的"The empty struct"一文,原文地址鏈接是http://dave.cheney.net/2014/03/25/the-empty-struct。

Introduction

這篇文章詳細(xì)介紹了我最喜歡的Go數(shù)據(jù)類型,空結(jié)構(gòu)體--struct{}。

空結(jié)構(gòu)體是沒有位段的結(jié)構(gòu)體,以下是空結(jié)構(gòu)體的一些例子:

type Q struct{}
var q struct{}

但是如果一個(gè)就結(jié)構(gòu)體沒有位段,不包含任何數(shù)據(jù),那么他的用處是什么?我們能夠利用空結(jié)構(gòu)體完成什么任務(wù)?

Width

在深入研究空結(jié)構(gòu)體之前,我想先簡短的介紹一下關(guān)于結(jié)構(gòu)體寬度的知識。

術(shù)語寬度來自于gc編譯器,但是他的詞源可以追溯到幾十年以前。

寬度描述了存儲一個(gè)數(shù)據(jù)類型實(shí)例需要占用的字節(jié)數(shù),由于進(jìn)程的內(nèi)存空間是一維的,我更傾向于將寬度理解為Size(這個(gè)詞實(shí)在不知道怎么翻譯了,請諒解)。

寬度是數(shù)據(jù)類型的一個(gè)屬性。Go程序中所有的實(shí)例都是一種數(shù)據(jù)類型,一個(gè)實(shí)例的寬度是由他的數(shù)據(jù)類型決定的,通常是8bit的整數(shù)倍。

我們可以通過unsafe.Sizeof()函數(shù)獲取任何實(shí)例的寬度:

var s string
var c complex128
fmt.Println(unsafe.Sizeof(s))    // prints 8
fmt.Println(unsafe.Sizeof(c))    // prints 16

http://play.golang.org/p/4mzdOKW6uQ

數(shù)組的寬度是他元素寬度的整數(shù)倍。

var a [3]uint32
fmt.Println(unsafe.Sizeof(a)) // prints 12

http://play.golang.org/p/YC97xsGG73

結(jié)構(gòu)體提供了定義組合類型的靈活方式,組合類型的寬度是字段寬度的和,然后再加上填充寬度。

type S struct {
        a uint16
        b uint32
}
var s S
fmt.Println(unsafe.Sizeof(s)) // prints 8, not 6

An empty struct

現(xiàn)在我們清楚的認(rèn)識到空結(jié)構(gòu)體的寬度是0,他占用了0字節(jié)的內(nèi)存空間。

var s struct{}
fmt.Println(unsafe.Sizeof(s)) // prints 0

由于空結(jié)構(gòu)體占用0字節(jié),那么空結(jié)構(gòu)體也不需要填充字節(jié)。所以空結(jié)構(gòu)體組成的組合數(shù)據(jù)類型也不會占用內(nèi)存空間。

type S struct {
        A struct{}
        B struct{}
}
var s S
fmt.Println(unsafe.Sizeof(s)) // prints 0

http://play.golang.org/p/PyGYFmPmMt

What can you do with an empty struct

由于Go的正交性,空結(jié)構(gòu)體可以像其他結(jié)構(gòu)體一樣正常使用。正常結(jié)構(gòu)體擁有的屬性,空結(jié)構(gòu)體一樣具有。

你可以定義一個(gè)空結(jié)構(gòu)體組成的數(shù)組,當(dāng)然這個(gè)切片不占用內(nèi)存空間。

var x [1000000000]struct{}
fmt.Println(unsafe.Sizeof(x)) // prints 0

http://play.golang.org/p/0lWjhSQmkc

空結(jié)構(gòu)體組成的切片的寬度只是他的頭部數(shù)據(jù)的長度,就像上例展示的那樣,切片元素不占用內(nèi)存空間。

var x = make([]struct{}, 1000000000)
fmt.Println(unsafe.Sizeof(x)) // prints 12 in the playground

http://play.golang.org/p/vBKP8VQpd8

當(dāng)然切片的內(nèi)置子切片、長度和容量等屬性依舊可以工作。

var x = make([]struct{}, 100)
var y = x[:50]
fmt.Println(len(y), cap(y)) // prints 50 100

http://play.golang.org/p/8cO4SbrWVP

你甚至可以尋址一個(gè)空結(jié)構(gòu)體,空結(jié)構(gòu)體是可尋址的,就像其他類型的實(shí)例一樣。

var a struct{}
var b = &a

有意思的是兩個(gè)空結(jié)構(gòu)體的地址可以相等。

var a, b struct{}
fmt.Println(&a == &b) // true

http://play.golang.org/p/uMjQpOOkX1

空結(jié)構(gòu)體的元素也具有一樣的屬性。

a := make([]struct{}, 10)
b := make([]struct{}, 20)
fmt.Println(&a == &b)       // false, a and b are different slices
fmt.Println(&a[0] == &b[0]) // true, their backing arrays are the same

http://play.golang.org/p/oehdExdd96

為什么會這樣?因?yàn)榭战Y(jié)構(gòu)體不包含位段,所以不存儲數(shù)據(jù)。如果空結(jié)構(gòu)體不包含數(shù)據(jù),那么就沒有辦法說兩個(gè)空結(jié)構(gòu)體的值不相等,所以空結(jié)構(gòu)體的值就這樣相等了。

a := struct{}{} // not the zero value, a real new struct{} instance
b := struct{}{}
fmt.Println(a == b) // true

http://play.golang.org/p/K9qjnPiwM8

有興趣可以參考這篇文章" Two distinct zero-size variables may have the same address in memory"。

struct{} as a method receiver

現(xiàn)在讓我們展示一下空結(jié)構(gòu)體如何像其他結(jié)構(gòu)體工作,空結(jié)構(gòu)體可以作為方法的接收者。

type S struct{}

func (s *S) addr() { fmt.Printf("%p\n", s) }

func main() {
        var a, b S
        a.addr() // 0x1beeb0
        b.addr() // 0x1beeb0
}

http://play.golang.org/p/YSQCczP-Pt

在這篇文章中空結(jié)構(gòu)體的地址是0x1beeb0,但是這個(gè)值可能隨著Go版本的不同而發(fā)生變化。

Wrapping up

非常感謝您讀完這篇冗長的文章,但是我還有一些其他的內(nèi)容需要說明,請見隨后更新。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,534評論 19 139
  • #mark- 01-指針和數(shù)組 //問題:指針類型的用途是什么? 答: 第一個(gè)用途, 取值的時(shí)候, 會根據(jù)指針類型...
    飛飛喵閱讀 906評論 0 2
  • 每日清晨,裹挾著一身汗珠匆匆趕著被地鐵“蹂躪”的路上,總是會經(jīng)過炒面君前的一塊空地,空地上的兩位步履蹣跚的老人總是...
    velaria閱讀 754評論 0 1
  • 生命中總是遇到那么幾個(gè)傻姑娘,愿意賠上青春不顧一切的去愛一個(gè)不愛她的人。 懷揣著希翼等待,說不定哪天就能感動(dòng)他...
    伊倩閱讀 439評論 1 2
  • 野生動(dòng)物第一個(gè)是老虎,有這個(gè)特質(zhì),只為了生存,它僅僅為了生存,這么簡單的命題,而且它是嗅覺非常敏銳的。希望咱們在野...
    jeffery工業(yè)物聯(lián)閱讀 153評論 0 0

友情鏈接更多精彩內(nèi)容