這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。
函數定義
type mytype int // 新的類型func (p mytype) funcname(q int) (r,s int) {return 0,0}
範圍
在 Go 中,定義在函數外的變數是全域的,那些定義在函數內部的變數,對於函數來說 是局部的。如果命名覆蓋——一個局部變數與一個全域變數有相同的名字——在函數 執行的時候,局部變數將覆蓋全域變數。
多值返回
func (file *File) Write(b []byte) (n int, err error)
Go得函數可以返回多個值
命名傳回值
Go 函數的傳回值或者結果參數可以指定一個名字,並且像原始的變數那樣使用,就像 輸入參數那樣。如果對其命名,在函數開始時,它們會用其類型的零值初始化。如果 函數在不加參數的情況下執行了 return 語句,結果參數會返回。
例:
func ReadFull(r Reader, buf []byte) (n int, err error) { for len(buf) > 0 && err == nil { var nr int nr, err = r.Read(buf) n += nr buf = buf[nr:len(buf)] } return }
延遲代碼defer
在 defer 後指定的 函數會在函數退出前調用。
func ReadWrite() bool { file.Open("file") defer file.Close() // file.Close()被添加到了defer列表 if failureX { return false } if failureY { return false } return true}
可以將多個函數放入 “延遲列表”中,例如:
for i:=0; i<5; i++ {defer fmt.Printf("%d ", i)}// 延遲的函數是按照後進先出(LIFO)的順序執行,所以上面的代碼列印:4 3 2 1 0。
利用 defer 甚至可以修改傳回值,假設正在使用命名結果參數和函數符號。
defer func() {/* ... */}() // ()在這裡是必須的
或者這個例子,更加容易瞭解為什麼,以及在哪裡需要括弧:
defer func(x int) { /* ... */}(5) // 為輸入參數 x 賦值 5
在這個(匿名)函數中,可以訪問任何命名返回參數:
func f() (ret int) { //ret初始化為零 defer func() { ret++ //ret增加為1 }() return 0 // 返回的是1而不是0}
變參
接受不定數量的參數的函數叫做變參函數。定義函數使其接受變參:
func myfunc(arg ...int) { }
arg ...int 告訴 Go 這個函數接受不定數量的參數。注意,這些參數的類型全部是 int。
在函數體中,變數 arg 是一個 int 類型的 slice:
for _, n := range arg { fmt.Printf("And the number is: %d\n", n)}
如果不指定變參的類型,預設是空的介面 interface{}(參閱第 5 章)。假設有另一
個變參函數叫做 myfunc2,下面的例子示範了如何向其傳遞變參:
func myfunc(arg ...int) { myfunc2(arg...) ← 按原樣傳遞 myfunc2(arg[:2]...) ← 傳遞部分}
函數作為值
Go 中函數也是值,函數可以賦值給變數:
func main() { a := func() { // 定義一個匿名函數,並賦值給a println("Hello") } a() // 調用函數}
回調
由於函數也是值,所以可以很容易的傳遞到其他函數裡,然後可以作為回調。
func printit(x int) { // 函數無傳回值 fmt.Printf("%v\n", x) // 僅僅列印}func callback(y int, f func(int)) { // f 將會儲存函數 f(y) // 調用回呼函數 f 輸入變數 y}
恐慌(Panic)和恢複(Recover)
Panic:是一個內建函數,可以中斷原有的控制流程程,進入一個令人恐慌的流程中。當函數F調用panic,函數F的執行被中斷,並且F中的延遲函數會正常執行,然後F返回到調用它的地方。在調用的地方,F的行為就像調用了panic。這一過程繼續向上,直到程式崩潰時所有goroutine返回。
恐慌可以直接調用panic產生。也可以由執行階段錯誤產生,例如訪問越界的數組。
Recover:是一個內建函數,可以讓進入令人恐慌的流程中的goroutine恢複過來。recover僅在延遲函數中有效。
在正常的執行過程中,調用recover會返回nil並且沒有其他任何效果。如果當期的goroutine陷入恐慌,調用recover可以捕獲到panic的輸入值,並且恢複正常的執行。
例:
這個函數檢查作為其參數的函數在執行時是否會產生 panic c: . func throwsPanic(f func()) (b bool) {//定義一個新函數 throwsPanic 接受一個函數作為參數(參看 “函數作為值”)。函 數 f 產生 panic,就返回 true,否則返回 false; defer func() { //定義了一個利用 recover 的 defer 函數。如果當前的 goroutine 產生了 panic,這個 defer 函數能夠發現。當 recover() 返回非 nil 值,設定 b 為 true; if x := recover(); x != nil { b = true } }() f() // 調用作為參數接收的函數。 return // 返回 b 的值。由於 b 是命名傳回值,無須指定 b。}