go的錯誤處理其實有點讓我意外,以前寫的DELPHI到前陣子寫的c#,都有一個TRY EXCEPT的寫法
try
zero := 0;
number := 1 div zero;
ShowMessage('number / zero = '+IntToStr(number));
except
ShowMessage('Unknown error encountered');
end;
try
{
StreamReader streamReader = new StreamReader(@"D:\XXX\QQ.text");
Console.WriteLine(streamReader.ReadToEnd());
Console.ReadKey();
}
catch( Exception ex )
{
Console.WriteLine(ex.Message);
Console.ReadKey();
}
上面的語法可以清楚的看出來,只要定義好TRY EXCEPT/TRY CATCH範圍,裡面寫的CODE只要發生錯言就會執行例外處理的CODE
可是呢...GO沒有!!!
所以就有一些錯誤事件要再處理
發生嚴重錯誤必須讓進行退出,嚴重的判斷標準是錯誤無法恢復導致程式無法執行或繼續執行或者繼續執行也得不到預定的結果,另一些場景就是程式啟動需要的初始化資料需要在DB中讀取,這個時DB庫無法讀取或者不存在配置項不可讀取,這個時候哪怕是執行下去程式也是毫無意義的,這個時候panic暴露出問題反而是更可取的方式。非嚴重的錯誤比如客戶端不合法的請求參數返回錯誤參數提示即可,讓調用者自己去處理問題,而不是自己panic掛掉。
快速退出錯誤處理。也就是下面需要模擬的try catch的行為。大多數情況下錯誤處理都應該使用判斷error的機制,但是有時函數調用棧很深,逐層返回錯誤可能需要寫很多冗餘代碼,這個時候可以使用panic讓程序的控制流直接跳到頂層的recover來進行處理。這種場景需要注意必須在包內就要recover。讓panic垮包傳遞可能會導致更複雜的問題,所以包的到處函數不應該產生panic。
根本上面落落長的說明,簡單說就是讓application直接掛掉,如果上k8s的話,panic會導致pod重啟,
所以不是發生問題直接噴panic就好。
package main
func main() {
panic("MDFK 2020")
}
執行結果
panic: MDFK 2020
goroutine 1 [running]:
main.main()
main.go:9 +0x45
exit status 2
## recover
簡單說就宣告好recover,當發生panic時,會讓原本application或是pod重啟的行為讓recover捕捉到,並讓panic轉成error的狀態。
以下面為範例
package main
import (
"fmt"
"os"
)
func main() {
defer func() {
if err := recover(); err != nil {
fmt.Println("hi recover:", err)
}
}()
_, err := os.Open("QQ.go")
if err != nil {
panic(err)
}
fmt.Printf("done")
}
執行結果
hi open QQ.go: The system cannot find the file specified.
## error
go的建議寫法就是用error來做錯誤處理,所以當function發生異常時,都會回傳一個error,讓呼叫的程式知道是否發生錯誤,but!!!因為都要加err,所以就變成go有名的err地獄,因為不管是呼叫什麼function都有一個回傳值叫error,跟TRY EXCEPT這種寫法比較來實行是很麻煩阿...
package main
import (
"errors"
"fmt"
)
func main() {
a := 1
b := 2
_, err := Bigger(a, b)
if err != nil {
fmt.Println("err:", err)
}
}
func Bigger(a int, b int) (bool, error) {
if a < b {
return false, errors.New("first small than second")
}
return true, nil
}
要如何拋出錯誤呢,很簡單喔只要打errors.New("oooooxxxx")
package main
import (
"errors"
"fmt"
)
func main() {
if err := makeerror(); err != nil {
fmt.Println("err:", err)
}
}
func makeerror() error {
return errors.New("make something error")
}
小小感想,寫習慣可以包try finally 跟try catch的程式後,golang的無盡ERR回傳值讓人覺得有點無奈RR,
希望還是可以用包TRY CATCH的方式來處理Error Handling,希望之後的版本能夠提供RR