Go語言學習(七)閉包和錯誤處理

來源:互聯網
上載者:User
1.閉包
Go語言中的閉包同樣也會引用到函數外的變數。閉包的實現確保只要閉包還被使用,那麼被閉包引用的變數會一直存在,例如:
package mainimport "fmt"func main(){    var j int = 5    a := func()(func()) { //圓括弧中的func()表示傳回值是一個func()函數        var i int = 10        return func() { //這裡返回一個匿名函數            fmt.Printf("i, j: %v, %v\n", i, j)        }    }() //花括弧後帶參數列表表示調用匿名函數,執行到這裡變數a就等於了一個函數了.    a() //調用函數a    j *= 2 //修改函數外部的變數j    a() //再次調用函數a}
運行結果:i, j: 10, 5i, j: 10, 10
在上面的例子中,變數 a 指向的閉包函數引用了局部變數 i 和 j , i 的值被隔離,在閉包外不能被修改,改變 j 的值以後,再次調用 a ,發現結果是修改過的值。在變數 a 指向的閉包函數中,只有內部的匿名函數才能訪問變數 i ,而無法通過其他途徑訪問到,因此保證了 i 的安全性。
2.錯誤處理

2.1 error介面

Go語言引入了一個關於錯誤處理的標準模式,即 error 介面,該介面的定義如下:type error interface {    Error() string}建立error通常如下:var e error = errors.New("...")//需要使用使用errors包對於大多數函數,如果要返回錯誤,大致上都可以定義為如下模式,將 error 作為多種傳回值中的最後一個,但這並非是強制要求:
func Foo(param int)(res int,err error){    //....}
調用時的代碼建議按如下方式處理錯誤情況:
n, err := Foo(0)if err != nil {    // 錯誤處理} else {    // 使用傳回值n}

2.2 defer關鍵字

Go語言中有種不錯的設計,即延遲(defer)語句,你可以在函數中添加多個defer語句。當函數執行到最後時,這些defer語句會按照逆序執行,最後該函數返回。特別是當你在進行一些開啟資源的操作時,遇到錯誤需要提前返回,在返回前你需要關閉相應的資源,不然很容易造成資源流失等問題。
func ReadWrite() bool {    file.Open("file")    // 做一些工作    if failureX {        file.Close()        return false    }    if failureY {        file.Close()        return false    }    file.Close()    return true}
我們看到上面有很多重複的代碼,Go的defer有效解決了這個問題。使用它後,不但代碼量減少了很多,而且程式變得更優雅。
func ReadWrite() bool {    file.Open("file")    defer file.Close() //保證資源正常關閉    if failureX {        return false    }    if failureY {        return false    }    return true}
如果有很多調用defer,那麼defer是採用後進先出模式
for i := 0; i < 5; i++ {    defer fmt.Printf("%d ", i) //輸出結果:4 3 2 1 0}
defer有點類似java中的try{}finall{}

2.3 panic和recover函數

Go語言有2個內建的函數panic()和recover(),用以報告和捕獲運行時發生的程式錯誤,與error不同,panic和recover一般用在函數內部。一定要注意不要濫用panic和recover,可能會導致效能問題,一般只在未知輸入和不可靠請求時使用。Go語言的錯誤處理流程:當一個函數在執行過程中出現了異常或遇到 panic(),正常語句就會立即終止,然後執行 defer 語句,再報告異常資訊,最後退出 goroutine。如果在defer中使用了recover()函數,則會捕獲錯誤資訊,使該錯誤資訊終止報告。如下樣本,例子來自網路
package mainimport ( "log"  //log包 "strconv" //字元轉換包)//捕獲因未知輸入導致的程式異常func catch(nums ...int) int {    defer func() {        //recover()可以捕獲運行時發生的異常,避免異常時程式直接over,通常用在defer函數內        if r := recover(); r != nil {             log.Println("[E]", r) //將捕獲的異常資訊通過log列印,而不會導致程式掛掉        }    }()    return nums[1] * nums[2] * nums[3] //index out of range}//主動拋出 panic,不推薦使用,可能會導致效能問題func toFloat64(num string) (float64, error) {    defer func() {        if r := recover(); r != nil {             log.Println("[W]", r)        }    }()    if num == "" {        panic("param is null") //主動拋出 panic    }    return strconv.ParseFloat(num, 10) }func main() {    catch(2, 8)    toFloat64("")}
運行結果:2016/03/26 20:16:03 [E] runtime error: index out of range2016/03/26 20:16:03 [W] param is null

最後補充下nil的介紹:

golang的nil在概念上和其它語言的null、None、nil、NULL一樣,都指代零值或空值。nil是預先說明的標識符,也即通常意義上的關鍵字。在golang中,nil只能賦值給指標、channel、func、interface、map或slice類型的變數。如果未遵循這個規則,則會引發panic。
相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.