Golang 內置方法append
用於向切片中追加一個或多個元素,實際項目中比較常見。git
其原型以下:github
func append(slice []Type, elems ...Type) []Type
本節不會對append
的使用方式詳細展開,而是重點介紹幾個使用中常見的誤區或者陷阱。golang
按照慣例,咱們先拿幾個小題目來檢測一下對append
的理解是否足夠深入。數組
函數Validation()
用於一些合法性檢查,每遇到一個錯誤,就生成一個新的error
並追加到切片errs
中, 最後返回包含全部錯誤信息的切片。 爲了簡單起見,假定函數發現了三個錯誤,以下所示:app
func Validation() []error { var errs []error append(errs, errors.New("error 1")) append(errs, errors.New("error 2")) append(errs, errors.New("error 3")) return errs }
請問函數Validation()
有什麼問題?函數
函數ValidateName()
用於檢查某個名字是否合法,若是不爲空則認爲合法,不然返回一個error
。 相似的,還能夠有不少檢查項,好比檢查性別、年齡等,咱們統稱爲子檢查項。 函數Validations()
用於收集全部子檢查項的錯誤信息,將錯誤信息彙總到一個切片中返回。工具
請問函數Validations()
有什麼問題?code
func ValidateName(name string) error { if name != "" { return nil } return errors.New("empty name") } func Validations(name string) []error { var errs []error errs = append(errs, ValidateName(name)) return errs }
前面的熱身題目均來源於實際項目(已經作了最大程度的精簡),分別表明一個本節將要介紹的陷阱。get
append
的本質是身切片中追加數據,而隨着切片中元素逐漸增長,當切片底層的數組將滿時,切片會發生擴容, 擴容會致使產生一個新的切片(擁有容量更大的底層數組),更多關於切片的信息,請查閱切片相關章節。原型
append
每一個追加元素,都有可能觸發切片擴容,也即有可能返回一個新的切片,這也是append
函數聲明中返回值爲切片的緣由。實際使用中應該老是接收該返回值。
上述題目一中,因爲初始切片長度爲0,因此實際上每次append
都會產生一個新的切片並迅速拋棄(被gc回收)。 原始切片並無任何改變。須要特別說明的是,無論初始切片長度爲多少,不接收append
返回都是有極大風險的。
另外,目前有不少的工具能夠自動檢查出相似的問題,好比Goland
IDE就會給出很明顯的提示。
向切片中追加一個nil
值是徹底不會報錯的,以下代碼所示:
slice := append(slice, nil)
通過追加後,slice的長度遞增1。
實際上nil
是一個預約義的值,即空值,因此徹底有理由向切片中追加。
上述題目二中,就是典型的向切片中追加nil
(當名字爲空時)的問題。單純從技術上講是沒有問題,但在題目二場景中就有很大的問題。
題目中函數用於收集全部錯誤信息,沒有錯誤就不該該追加到切片中。因後,後續極有可能會跟據切片的長度來判斷是否有錯誤發生,好比:
func foo() { errs := Validations("") if len(errs) > 0 { println(errs) os.Exit(1) } }
若是向切片中追加一個nil
元素,那麼切片長度則再也不爲0,程序極可能所以而退出,更糟糕的是,這樣的切片是沒有內容會打印出來的,這無疑又增長了定位難度。
贈人玫瑰手留餘香,若是以爲不錯請給個贊~ 你的鼓勵將成爲我繼續寫做的動力!
本篇文章已歸檔到GitHub項目,求星~ 點我即達