Go內置零值標識符zero
大家學習和使用 Go 語言時,有一個神奇的概念:零值(zero-values)。零值這個名字是具體誰起的,又是從哪里先開始喊起的,已經難以考究了。
每次有新同學剛開始轉語言,工程上總會提到這個,想要試圖改變零值。又或是沒考慮到,一旦程序用了 0 作為 default 值,又要兼容零值的問題。
今天給大家分享一個關于零值的新提案,目測已經八九不離十了(在發(fā)布此文時,該提案已被正式 accepted)。
快速復習零值
基礎類型的例子如下:
func?main()?{ ?var?i?int ?var?f?float64 ?var?b?bool ?var?s?string ?fmt.Printf("%v?%v?%v?%q\n",?i,?f,?b,?s) }
輸出結果:
0 0 false ""
復合類型的例子如下:
type?Person?struct?{ ?Name???string ?Age????int ?Weight?float64 } func?main()?{ ?var?p?Person ?var?m?map[int]string ?var?s?[]string ?fmt.Printf("%#v\n%#v\n%#v\n",?p,?m,?s) }
輸出結果:
main.Person{Name:"", Age:0, Weight:0}
map[int]string(nil)
[]string(nil)
類型和零值的映射表格如下:
數(shù)據(jù)類型 | 零值 |
---|---|
int, int8, int16, int32, int64 | 0 |
uint, uint8, uint16, uint32, uint64 | 0 |
uintptr | 0 |
float32, float64 | 0 |
byte | 0 |
rune | 0 |
string | "" (empty string) |
complex64, complex128 | (0,0i) |
arrays of non-nillable types | array of zero-values |
arrays of nillable types | array of nil-values |
新提案:預聲明標識符 zero
背景
事情的起因是:@Nathan Cormier 在社區(qū)提了吐槽和提案《proposal: builtin: zero function[1]》:
他表示:Go 語言目前提供了幾種獲取類型零值的方法,如果能有一種統(tǒng)一的方法來實現(xiàn)這一點,代碼的可讀性會更高。
有同學深思,哪來的幾種?其實可以:
var?z?MyType return?z
還可以:
return?*new(MyType)
初始化結構體后出來的都是零值。
緊接著就會遇到開頭提到的問題,你怎么知道這是零值,還是缺省值?難以直接判別。
更重要的是,這不太符合 Go 的設計哲學,又是多種途徑,還和缺省值產生混淆。顯然和主打工程的 Go 的發(fā)展路子不合。
解決方案
新增 zero 標識符
這次經過一番撕扯,最終是由 Go 核心團隊負責人 @Russ Cox 出來主持大局,提出了新提案并一路向前。
Go 將會增加一個新的預定義標識符 zero
,它是一個無類型的零值,適用于數(shù)組和結構體類型。
以下是 zero 的類型簽名:
//?zero?is?a?predeclared?identifier?representing?the?zero?value //?for?array?and?struct?types. var?zero?Type
他不會像 nil 一樣。我們可以對照看看 nil 的類型簽名:
//?nil?is?a?predeclared?identifier?representing?the?zero?value?for?a //?pointer,?channel,?func,?interface,?map,?or?slice?type. var?nil?Type?//?Type?must?be?a?pointer,?channel,?func,?interface,?map,?or?slice?type
Nil 受限于 chan、func、interface、map、slice、pointer 等類型。
zero 可賦值性規(guī)則
zero
的可賦值性規(guī)則如下:
- 絕大部分場景下,
zero
可以分配給任何類型 T 的任何變量。(T 指的是結構體) - 不可以的場景,已經具有短零(指的是:0、“”、nil)的變量,不可以分配。
- 泛型場景下,即使 T 是帶有 any 約束條件的類型參數(shù),也是可以分配的。
- 上述提到的可賦值性,包含函數(shù)參數(shù)和返回值,例如:
f(zero)
和return zero, err
也是正常有效的,也能夠用于值比較。
可能會有的同學擔心,zero
和短零(0, "", or nil)產生沖突。對此可以放心。在設計的規(guī)則上:zero
在短零有效的任何地方都無效,所以在使用上不會產生混淆。
解決了什么問題
實際問題上,解決了以下幾點:
- 在通用代碼中需要引用零值,發(fā)現(xiàn)大家經常建議使用
*new(T)
來做初始化。導致經常要向新用戶解釋這一點非常麻煩。Go 需要更簡潔的方法。 - 在泛型代碼中便于與零值比較,在 cmp: add Or[2] 中出現(xiàn)了這一實際編碼訴求。
- 縮短錯誤返回,新的
return zero, err
會比原有的return time.Time{}, err
更好。
通用概念來講:
- 零值是 Go 中的一個重要概念。但某些類型對此還沒有具體的名稱,現(xiàn)在可以叫他
zero
。 - Go 需要一個機制來將其值和零值進行比較,來解決前文提到的缺省值和零值無法很好識別的問題。
一些問題和爭論
會有同學認為,現(xiàn)有的 return _, _, err
會比 return zero, zero, err
更短并且感覺更好。(但在清晰程度上會不如 zero 和 nil)
也有同學會認為自己寫一個這個實現(xiàn)也很簡單,是否有必要為此專門增加一個 zero
預定義值?
可以用泛型如下實現(xiàn):
func?Zero[T?any]()?T?{ ????var?v?T ????return?v }
對此在很多提案上,都很容易陷入怪圈。有了泛型后,照實現(xiàn)來講,什么都可以自己寫一份。
也會有一派認為以后判斷錯誤類型要變成:
if?err?!=?zero?{ ??... }
會非常奇怪。以后可能會出現(xiàn) if err != nil
和 if err != zero
的奇怪代碼場景。
注:這個場景是假定 zero
標識符能適用于所有的數(shù)據(jù)類型下才會出現(xiàn)。本次并不存在。
總結
目前的社區(qū)討論比較發(fā)散,認為 zero
標識符未來也可以取代所有的零值。但從提案內容和提交的 SPEC CL 來看,@Russ Cox 一直針對的是數(shù)組和結構體的零值場景去使用 zero
標識符。
這個提案已經進入到最終階段,已經被正式接受,基本跑不了了。
以后我們在不同類型下對零值判斷,可以基于:
數(shù)據(jù)類型 | 使用什么作為零值 |
---|---|
int 等數(shù)字類型 | 使用 0 |
string 字符串類型 | 使用 ”“(空字符串) |
slice, map, function, pointer, channel, and interface 等類型 | 使用 nil |
array 和 struct 類型 | 可使用 zero 標識符 |
雖然在使用上,做了一定的使用場景的切分,也就是只有數(shù)組和結構體類型使用 zero 標識符。但對于寫 Go 用戶而言,認知上是會存在明確混淆的。
以后你給其他同學解釋零值,解釋起得區(qū)分兩種場景來介紹。我感覺還不如 zero 標識符一統(tǒng)零值天下。但很可惜,本次提案暫時并沒有這個計劃。
到此這篇關于Go內置零值標識符zero的文章就介紹到這了,更多相關Go零值內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
Golang限流器time/rate設計與實現(xiàn)詳解
在?Golang?庫中官方給我們提供了限流器的實現(xiàn)golang.org/x/time/rate,它是基于令牌桶算法(Token?Bucket)設計實現(xiàn)的,下面我們就來看看他的具體使用吧2024-03-03golang中的string與其他格式數(shù)據(jù)的轉換方法詳解
這篇文章主要介紹了golang中的string與其他格式數(shù)據(jù)的轉換方法,文章通過代碼示例介紹的非常詳細,對大家的學習或工作有一定的幫助,需要的朋友可以參考下2023-10-10Go gorilla securecookie庫的安裝使用詳解
這篇文章主要介紹了Go gorilla securecookie庫的安裝使用詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-08-08