? ? ? ?函數(shù)包含連續(xù)的執(zhí)行語句,可以在代碼中通過調(diào)用函數(shù)來執(zhí)行它們。函數(shù)能將復(fù)雜的邏輯轉(zhuǎn)換為一塊塊的代碼塊,使得更具可讀性,另外有一些公共的函數(shù),可以讓團隊合作更加便利,在Golang當(dāng)中,函數(shù)和Node.js稍微有一點點的不同,下面由我來講解講解。
? ? ? ?首先是函數(shù)的聲明,在Golang中函數(shù)的聲明就類似強類型的node.js函數(shù)聲明,func name(param list) (result-list) {/** body **/}, 形式參數(shù)列表指定了一組變量的參數(shù)名和參數(shù)類型,它們的實參由調(diào)用這個函數(shù)的調(diào)用方傳遞過來,返回類型稍微有點不同,在Golang里面除了沒有返回值的函數(shù),其他都要注明返回類型,另外它也支持多個返回值。函數(shù)的類型稱作函數(shù)簽名,當(dāng)兩個函數(shù)擁有相同的形參列表和返回列表時,我們就說他們的簽名一樣。每次我們調(diào)用的時候,參數(shù)要一一對應(yīng),順序也要相同,Golang函數(shù)參數(shù)沒有默認值的概念。
? ? ? 那么在Golang當(dāng)中,函數(shù)如何處理錯誤呢?我們可以利用它可以有多個返回值的特性,將錯誤返回給調(diào)用方,我們習(xí)慣上,把錯誤的變量放在最后一個結(jié)果返回。如果錯誤只有一種情況,通常返回布爾值,比如在緩存當(dāng)中取值,如果鍵值不存在就會返回錯誤,那我們就可以這樣寫:value,ok := cache.query(key), 如果ok是真就是正常返回了鍵值,如果ok是假就說明鍵值對不存在。錯誤只有一種的情況在現(xiàn)實的業(yè)務(wù)邏輯當(dāng)中,其實很少,大部分都是一些未考慮到或者意外的錯誤,比如連接不上數(shù)據(jù)庫,內(nèi)存不足等等,這個時候我們通常將錯誤封裝到最后一個返回值里面,調(diào)用方先查看這個錯誤存不存在,如果存在,先處理錯誤,如果不存在,就繼續(xù)下面的邏輯,比如調(diào)用http的get請求獲取信息,resp,err := http.get(url); if err != nil { return nil, err}; 。另外,對于錯誤,我們可以采用fmt.Errorf的fmt.Sprintf函數(shù)格式化錯誤信息并且返回一個新的錯誤值,我們把原始的錯誤消息不斷添加上去,構(gòu)成一個錯誤鏈條,當(dāng)錯誤最終到達main函數(shù)的時候,就能得到一個清晰的從根本原因到總體故障的因果鏈。一種更加優(yōu)雅的方式輸出錯誤是自定義打印的格式,包含時間和日期、內(nèi)容,只記錄下錯誤,讓程序繼續(xù)運行,這樣就減少了打斷程序運行的頻率。
? ? ? ?在Golang當(dāng)中,和Node.js一樣,它還有一種很特殊的函數(shù),叫做匿名函數(shù)。我們知道,命名函數(shù)只能在包級的作用域進行聲明,但是匿名函數(shù)可以突破這個限制。比如下面這個平方函數(shù):
func? squares()? func()? int {
? ?var x int
? ?return func() int {
????????x++
????????return x * x
? ?}
}
當(dāng)我們在main函數(shù)里面這樣調(diào)用的時候,就會把x的作用域擴大了
func main() {
????f := squares()?
? ? fmt.Println(f()) // 1
? ? ?fmt.Println(f()) // 4
? ? fmt.Println(f())? // 9
? ? fmt.Println(f()) // 16????
}