這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。
36.蛤蟆筆記go語言——函數
函數是構建Go程式的基礎組件.Go不允許函數嵌套。然而你可以利用匿名函數實現它.
範圍
在Go中,定義在函數外的變數是全域的,那些定義在函數內部的變數,對於函數來說是局部的。如果命名覆蓋——一個局部變數與一個全域變數有相同的名字——在函數執行的時候,局部變數將覆蓋全域變數。
代碼:
package main
var a = 6
func main() {
p()
q()
p()
}
func p() {
println(a)
}
func q() {
a := 5
println(a)
}
輸出:
6
5
6
多值返回
Go一個非常特別的特性(對於編譯語言而言)是函數和方法可以返回多個值(Python 和 Perl 同樣也可以)。這可以用於改進一大堆在 C 程式中糟糕的慣例用法:修改參數的方式,返回一個錯誤(例如遇到EOF則返回-1)。在Go中,Write返回一個計數值和一個錯誤:“是的,你寫入了一些位元組,但是由於裝置異常,並不是全部都寫入了。”
代碼:
package main
func main() {
a :=[]byte{'1', '2', '3', '4'}
var xint
println(len(a))
for i:= 0; i < len(a); {
x,i = nextInt(a, i)
println(x)
}
}
func nextInt(b []byte, i int) (int, int) {
x := 0
// 假設所有的都是數字
for ; i< len(b); i++ {
x= x*10 + int(b[i]) - '0'
}
returnx, i
}
沒有元組作為原生類型,多傳回值可能是最佳的選擇。你可以精確的返回希望的值,而無須重載域空間到特定的錯誤訊號上。
命名傳回值
Go函數的傳回值或者結果參數可以指定一個名字,並且像原始的變數那樣使用,就像輸入參數那樣。如果對其命名,在函數開始時,它們會用其類型的零值初始化;如果函數在不加參數的情況下執行了 return語句,結果參數的當前值會作為傳回值返回。用這個特性,允許(再一次的)用較少的代碼做更多的事。
名字不是強制的,但是它們可以使得代碼更加健壯和清晰:這是文檔。例如命名int類型的nextPos傳回值,就能說明哪個代表哪個。
由於命名結果會被初始化並關聯於無修飾的return,它們可以非常簡單並且清晰。
延遲代碼
假設有一個函數,開啟檔案並且對其進行若干讀寫。在這樣的函數中,經常有提前返回的地方。如果你這樣做,就需要關閉正在工作的檔案描述符。
為瞭解決這些,Go有了defer語句。在defer後指定的函數會在函數退出前調用。
延遲的函數是按照後進先出(LIFO)的順序執行.
函數符號也就是被叫做閉包的東西
變參
接受變參的函數是有著不定數量的參數的。為了做到這點,首先需要定義函數使其接受變參.
arg ...int告訴Go這個函數接受不定數量的參數。注意,這些參數的類型全部是int。
函數作為值
就像其他在Go中的其他東西一樣,函數也是值而已。
例如代碼:
package main
func main() {
a :=func() {
println("Hello")
}
a()
}
回調
當函數作為值時,就可以很容易的傳遞到其他函數裡,然後可以作為回調。
恐慌(Panic)和恢複(Recover)
Go沒有像Java那樣的異常機制:不能拋出一個異常。作為替代,它使用了恐慌和恢複(panic-and-recover)機制。一定要記得,這應當作為最後的手段被使用,你的代碼中應當沒有,或者很少的令人恐慌的東西。這是個強大的工具,明智的使用它。
Panic
panic是一個內建函數,可以中斷原有的控制流程程,進入一個令人恐慌的流程中。當函數F調用panic,函數F的執行被中斷,並且F中的延遲函數會正常執行,然後F返回到調用它的地方。在調用的地方,F的行為就像調用了panic。這一過程繼續向上,直到程式崩潰時的所有goroutine返回。恐慌可以直接調用panic產生。也可以由執行階段錯誤產生,例如訪問越界的數組。
Recover
一個內建的函數,可以讓進入令人恐慌的流程中的 goroutine 恢複過來。recover僅在延遲函數中有效。
對應異常機制,Go 的這種錯誤機制或許可以叫做恐慌機制:當你遇到它時應該感到恐慌(panic),然後應該恢複(recover)它.在正常的執行過程中,調用recover會返回nil並且沒有其他任何效果。如果當前的goroutine陷入恐慌,調用recover可以捕獲到panic的輸入值,並且恢複正常的執行。