溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

go的錯誤處理

發布時間:2020-08-10 00:01:19 來源:網絡 閱讀:343 作者:wangchunyi123 欄目:編程語言

一 error接口

        GO語言中的error類型實際上是抽象Error()方法的error接口

            type error interface{

                    Error()    string

             }

          GO語言使用該接口進行標準的錯誤處理。

           對于大多數函數,如果要返回錯誤,大致上都可以定義為如下模式,將error作為多種返回值中的最后一個,但這并非是強制要求:

            func Foo (param int) (n int,err error){

                // .....   

            }

            調用時的代碼建議按照如下方式處理錯誤情況

            n,err := Foo(0)

            if err != nil {

                //錯誤處理

            }else{

                //使用返回值n

             }

        看下面的例子綜合了一下error接口的用法:

        

package main

import(    
     "fmt"
    )
//自定義錯誤類型
type ArithmeticError struct {
    error   //實現error接口
}
//重寫Error()方法
func (this *ArithmeticError) Error() string {
    return "自定義的error,error名稱為算數不合法"
 }
 
 //定義除法運算函數
func Devide(num1, num2 int) (rs int, err error) { 
   if num2 == 0 { 
       return 0, &ArithmeticError{}
    } else {
       return num1 / num2, nil
    }
}
func main() { 
       var a, b int
    fmt.Scanf("%d %d", &a, &b)

    rs, err := Devide(a, b)
     if err != nil {
        fmt.Println(err)
    } else {
        fmt.Println("結果是:", rs)
    }
}

   

運行,輸入參數5 2(正確的情況):

5 2結果是: 2

 

若輸入5 0(產生錯誤的情況):

5 0自定義的error,error名稱為算數不合法

 

        通過上面的例子可以看出error類型類似于Java中的Exception類型,不同的是Exception必須搭配throw和catch使用。


二、defer--延遲語句

        在GO語言中,可以使用關鍵字defer向函數注冊退出調用,即主函數退出時,defer后的函數才會被調用。

        defer語句的作用是不管程序是否出現異常,均在函數退出時自動執行相關代碼。(相當于Java中的finally )

當函數執行到最后時,這些defer語句會按照逆序執行,最后該函數返回。

例如:

go的錯誤處理

package main

import (    "fmt")

func main() {    for i := 0; i < 5; i++ {
        defer fmt.Println(i)
    }
}

go的錯誤處理

 

其執行結果為:

43210

 

defer語句在聲明時被加載到內存(多個defer語句按照FIFO原則) ,加載時記錄變量的值,而在函數返回之后執行,看下面的例子:

例子1:defer語句加載時記錄值

go的錯誤處理

func f1() {
    i := 0
    defer fmt.Println(i) //實際上是將fmt.Println(0)加載到內存
    i++    return}
func main() {
    f1()
}

go的錯誤處理

 

其結果顯然是0

例子2:在函數返回后執行

go的錯誤處理

func f2() (i int) {    var a int = 1
    defer func() {
        a++
        fmt.Println("defer內部", a)
    }()    return a
}
func main() {
    fmt.Println("main中", f2())
}

go的錯誤處理

 

其結果是

 

defer內部 2main中 1

 

 

 

例子3:defer語句會讀取主調函數的返回值,并對返回值賦值.(注意和例子2的區別)

go的錯誤處理

func f3() (i int) {
    defer func() {
        i++
    }()    return 1}
func main() {
    fmt.Println(f3())
}

go的錯誤處理

 

其結果竟然是2.

通過上面的幾個例子,自然而然會想到用defer語句做清理工作,釋放內存資源(這樣你再也不會為Java中的try-catch-finally層層嵌套而苦惱了)

例如關閉文件句柄:

srcFile,err := os.Open("myFile")
defer srcFile.Close()

 

關閉互斥鎖:

mutex.Lock()
defer mutex.Unlock()

 

上面例子中defer語句的用法有兩個優點:

1.讓設計者永遠也不會忘記關閉文件,有時當函數返回時常常忘記釋放打開的資源變量。

2.將關閉和打開靠在一起,程序的意圖變得清晰很多。

下面看一個文件復制的例子:

go的錯誤處理

package main

import (    
        "fmt"
    "io"
    "os"
    )

func main() {
    copylen, err := copyFile("dst.txt", "src.txt")
        if err != nil { 
               return
    } else {
        fmt.Println(copylen)
    }

}
//函數copyFile的功能是將源文件sec的數據復制給dst
func copyFile(dstName, srcName string) (copylen int64, err error) {
    src, err := os.Open(srcName)
        if err != nil {
                return
    }
//當return時就會調用src.Close()把源文件關閉
    defer src.Close()
    dst, err := os.Create(dstName)
     if err != nil { 
          return
    }
       //當return是就會調用src.Close()把目標文件關閉
     defer dst.Close()
     return io.Copy(dst, src)
}

go的錯誤處理

 

可以看到確實比Java簡潔許多。

三panic-recover運行時異常處理機制

Go語言中沒有Java中那種try-catch-finally結構化異常處理機制,而使用panic()函數答題throw/raise引發錯誤,

然后在defer語句中調用recover()函數捕獲錯誤,這就是Go語言的異?;謴蜋C制——panic-recover機制

兩個函數的原型為:

func panic(interface{})
//接受任意類型參數 無返回值
func recover() interface{}
//可以返回任意類型 無參數

 

一定要記住,你應當把它作為最后的手段來使用,也就是說,你的代碼中應當沒有,或者很少有panic的東西。這是個強大的工具,請明智地使用
它。那么,我們應該如何使用它呢?

panic()
是一個內建函數,可以中斷原有的控制流程,進入一個令人panic(恐慌即Java中的異常)的流程中。當函數F調用panic,函數F的執行被中
斷,但是F中的延遲函數(必須是在panic之前的已加載的defer)會正常執行,然后F返回到調用它的地方。在調用的地方,F的行為就像調用了panic。這一
過程繼續向上,直到發生panic的goroutine中所有調用的函數返回,此時程序退出。異??梢灾苯诱{用panic產
生。也可以由運行時錯誤產生,例如訪問越界的數組。

recover()
是一個內建的函數,可以讓進入令人恐慌的流程中的goroutine恢復過來。recover僅在延遲函數中有效。在正常
的執行過程中,調用recover會返回nil,并且沒有其它任何效果。如果當前的goroutine陷入panic,調用
recover可以捕獲到panic的輸入值,并且恢復正常的執行。

一般情況下,recover()應該在一個使用defer關鍵字的函數中執行以有效截取錯誤處理流程。如果沒有在發生異常的goroutine中明確調用恢復

過程(使用recover關鍵字),會導致該goroutine所屬的進程打印異常信息后直接退出。

這里結合自定義的error類型給出一個使用panic和recover的完整例子:

go的錯誤處理

package main

import (    
"fmt"
)
//自定義錯誤類型
type ArithmeticError struct {
    error
}
//重寫Error()方法
func (this *ArithmeticError) Error() string {
    return "自定義的error,error名稱為算數不合法"
    }
//定義除法運算函數***這里與本文中第一幕①error接口的例子不同
func Devide(num1, num2 int) int {    
    if num2 == 0 {
        panic(&ArithmeticError{}) 
        //當然也可以使用ArithmeticError{}同時recover等到ArithmeticError類型
    } else {
            return num1 / num2
    }
}
func main() {
    var a, b int
    fmt.Scanf("%d %d", &a, &b)

    defer func() {
             if r := recover(); r != nil {
               fmt.Printf("panic的內容%v\n", r)
                 if _, ok := r.(error); ok {
                fmt.Println("panic--recover()得到的是error類型")
            }
            if _, ok := r.(*ArithmeticError); ok {
                fmt.Println("panic--recover()得到的是ArithmeticError類型")
            }
            if _, ok := r.(string); ok {
                fmt.Println("panic--recover()得到的是string類型")
            }
        }
    }()

    rs := Devide(a, b)
    fmt.Println("結果是:", rs)
}

go的錯誤處理

 

其執行的結果為:

使用與上面相同的測試數據,輸入5 2得:

5 2結果是: 2

 

輸入5 0得:

5 0panic的內容自定義的error,error名稱為算數不合法
panic--recover()得到的是error類型
panic--recover()得到的是ArithmeticError類型

 

可見已將error示例程序轉換為了Java中的用法,但是在大多數程序中使用error處理的方法較多。

需要注意的是:defer語句定義的位置 如果defer放在了

 rs := Devide(a, b)語句之后,defer將沒有機會執行即:

go的錯誤處理

rs := Devide(a, b)
    defer func() {        
    if r := recover(); r != nil {
            fmt.Printf("panic的內容%v\n", r)            
            if _, ok := r.(error); ok {
                fmt.Println("panic--recover()得到的是error類型")
            }            if _, ok := r.(*ArithmeticError); ok {
                fmt.Println("panic--recover()得到的是ArithmeticError類型")
            }            if _, ok := r.(string); ok {
                fmt.Println("panic--recover()得到的是string類型")
            }
        }
    }()


向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

亚洲午夜精品一区二区_中文无码日韩欧免_久久香蕉精品视频_欧美主播一区二区三区美女