錯誤處理的精髓:快速了解Go語言的 error、panic和recover

更新於 2024/09/06閱讀時間約 12 分鐘


raw-image

👨‍💻簡介

在軟體開發中,錯誤無所不在。無論是網路請求失敗、檔案不存在,還是數學計算錯誤,處理錯誤是任何開發者的日常工作,系統的穩定度基本取決於對於錯誤處理是否全面,好的錯誤處理也可以產生適當的錯誤訊息,讓 Debug 更加容易。在Go語言中,有一些獨特的功能在處理錯誤和資源管理方面非常有用。,其中包括errorpanicrecover。今天就來介紹這三個關鍵字與錯誤處理的簡單用法。

Error

什麼是Error?

在Go中,Error是一個擁有error interface的類型,可以看到他只有一個方法,該方法主要用來描述一個錯誤的字串。

type error interface {
Error() string
}

如何產生錯誤訊息

  1. errors.New() 使用方式很簡單,在裡面放入要顯示的錯誤訊息
package main

import (
"errors"
"fmt"
)
func main() {
err := errors.New("This is a custom error message")
fmt.Println(err.Error()) // output:This is a custom error message
}

2. fmt.Errorf() 主要用在格式化錯誤訊息的情況下

package main

import (
"fmt"
)
func main() {
name := "John"
err := fmt.Errorf("Hello, %s! This is a custom error message", name)
fmt.Println(err.Error()) // output:Hello, John! This is a custom error message
}

Error用途

我們通常將Error用來當作函數的返回值,方便我們在調用函數時檢查錯誤:

func divide(x, y int) (int, error) {
if y == 0 {
return 0, errors.New("division by zero")
}
return x / y, nil
}

在範例中,我們透過errors.New創建一個新的Error實例,以表示除以零的錯誤情況。

panic與recover

什麼是panic?

在Go中,panic是一個內建函數,用於引發運行時異常或嚴重錯誤。通常情況下,我們應該避免使用panic,除非出現不可恢復的錯誤。

Panic是Go語言中的一種異常情況,表示程式遇到了一個無法處理的錯誤。當Panic發生時,程式會立即停止執行並打印Panic訊息,然後退出。Panic通常用於表示嚴重的錯誤,如空指標引用或陣列越界。

什麼是recover?

recover是Go語言中的一個內建函數,用於在發生panic時恢復程序的正常執行流程。它用於捕獲panic引發的錯誤,並允許程序繼續運行而不崩潰。

如何處理panic

為了處理panic,我們會使用recover。底下簡單使用兩者當作範例:

package main

import "fmt"
func main() {
defer handlePanic()
doSomething()
}
func doSomething() {
panic("發生了一個嚴重錯誤")
}
func handlePanic() {
if r := recover(); r != nil {
fmt.Println("恢復了panic:", r)
}
}

可以看到,doSomething函數引發了一個panic,但由於我們在main函數中使用了deferrecover,程序不會崩潰,而是執行了handlePanic函數,並輸出了錯誤訊息。需要注意的是,recover只能在defer中執行

常見用法

函數返回錯誤

當函數執行過程中遇到錯誤時,通常會將一個 error 類型的值作為返回值,以便呼叫方可以檢查和處理錯誤。

func Divide(a, b float64) (float64, error) {
if b == 0 {
return 0, errors.New("division by zero")
}
return a / b, nil
}

錯誤處理

在呼叫函數時,通常會檢查返回的 error 是否為 nil,以判斷是否發生了錯誤。如果錯誤不為 nil,則需要採取適當的措施來處理錯誤,比如記錄錯誤日誌、返回錯誤訊息給使用者等。

result, err := Divide(10.0, 0.0)
if err != nil {
log.Println("Error:", err)
// 進一步處理錯誤,如返回錯誤響應給使用者
}

自定義錯誤類型

因為Error是一個 interface,所以我們也可以實作自己的 error struct,有時會需要自定義錯誤類型,方便我們更好描述特定類型的錯誤

// 自定義 error type
type MyError struct {
Code int
Message string
}

// 實現 error interface的 Error 方法
func (e *MyError) Error() string {
return fmt.Sprintf("Error %d: %s", e.Code, e.Message)
}
func main() {
// 簡單建立自己的error
err := &MyError{
Code: 404,
Message: "Page not found",
}
// 調用自己的error 方法
fmt.Println("Error:", err.Error())
}

錯誤類型判斷

還有一種常見的做法是將error搭配 type assertion進行錯誤類型判斷

package main

import (
"errors"
"fmt"
)
// 自定義 error type
type MyError struct {
Code int
Message string
}
func (e *MyError) Error() string {
return fmt.Sprintf("Error %d: %s", e.Code, e.Message)
}
func main() {
err := processRequest(0)
switch e := err.(type) {
case nil:
fmt.Println("Request processed successfully.")
case *MyError:
fmt.Printf("Custom Error: %v\n", e)
// 處理自定義錯誤
case error:
fmt.Printf("Generic Error: %v\n", e)
// 處理其他錯誤
default:
fmt.Println("Unknown error.")
}
}
func processRequest(param int) error {
if param == 0 {
return &MyError{Code: 500, Message: "Internal Server Error"}
} else if param < 0 {
return errors.New("Negative parameter value")
}
return nil
}

實際應用

1. 檔案操作

  • 場景:讀取檔案時檔案不存在的情況。
package main

import (
"fmt"
"os"
)
func main() {
_, err := os.Open("non_existent_file.txt")
if err != nil {
if os.IsNotExist(err) {
fmt.Println("檔案不存在。")
} else {
fmt.Println("錯誤:", err)
}
}
}

2. 網路通訊

  • 場景:嘗試建立網路連線時timeout的情況。
package main

import (
"fmt"
"net"
"time"
)
func main() {
_, err := net.DialTimeout("tcp", "example.com:8080", time.Second)
if err != nil {
fmt.Println("錯誤:", err)
}
}

3. 資料庫操作

  • 場景:執行 SQL 查詢時發生語法錯誤的情況。
package main

import (
"database/sql"
"fmt"
_ "github.com/go-sql-driver/mysql"
)
func main() {
db, _ := sql.Open("mysql", "user:password@tcp(localhost:3306)/database")
_, err := db.Exec("SELECT * FROM non_existent_table")
if err != nil {
fmt.Println("錯誤:", err)
}
}

4. 使用者輸入驗證

  • 場景:驗證使用者輸入是否為數字。
package main

import (
"fmt"
"strconv"
)
func main() {
userInput := "abc"
_, err := strconv.Atoi(userInput)
if err != nil {
fmt.Println("無效的輸入:", err)
}
}

5. 異常情況處理

  • 場景:處理不可預見的系統錯誤。
package main

import (
"fmt"
"os"
)
func main() {
file, err := os.Open("/dev/zero")
if err != nil {
panic(err)
}
defer file.Close()

fmt.Println("File opened successfully.")
}

小結

錯誤處理三劍客,errorpanicrecover是強大的工具,它能讓你的程式碼更容易讀懂、容易維護,同時也能確保資源被妥善釋放,處理錯誤也更加方便。

📚Reference

avatar-img
17會員
83內容數
golang
留言0
查看全部
avatar-img
發表第一個留言支持創作者!
Alan的開發者天地 的其他內容
👨‍💻簡介 當我們在寫程式時,有時候會需要在程式結束時關閉某些資源,而defer這個關鍵字,可以讓你輕鬆的實現,下面來簡單介紹一下defer以及常用的範例。,它為程式設計師提供了一種簡單而強大的工具,用於管理資源和確保程式的正確執行。
👨‍💻簡介 在Go中,假如我要判斷一個資料類型是甚麼,該怎麼做呢? Golang有一個功能叫做Type Assertions(類型斷言),它的作用就是能夠在運行時檢查我的資料類型,讓我在傳遞類型時能確保資料類型是正確的。
👨‍💻簡介 make函數在slice、map和之後會介紹到的channel的初始化中扮演著關鍵的角色。本文將會簡單介紹make函數的用法,以及在初始化不同資料結構時的差異,讓你更好地理解和利用make函數。
👨‍💻簡介 套件(Package)在Golang中扮演著組織和管理程式碼的重要角色。 package就像工具箱一樣,裡面裝滿各種不同的工具,每個工具都有特定的功能。這些工具能夠幫助你完成不同的任務,從修理家具到蓋小屋,樣樣都行。
👨‍💻簡介 在Go語言中,Interface 是一個重要且強大的概念。Interface提供了一種方式來定義對象之間的契約,讓你可以設計更具有靈活性和可擴展性的程式碼。 你可以把Interface想像成是一種約定,讓不同的東西彼此溝通的方式變得特別靈活和好擴充,告訴程式裡的各個元件彼此要怎麼合作
👨‍💻簡介 在程式開發的世界中,我們經常需要處理各式各樣的資料,可能是一個人的個人資訊,也可能是一個商品的詳細訊息。當我們面對這麼多的資料時,如何將它們有系統地整理起來,讓我們能夠輕鬆地找到所需,便成了一個重要的課題。這時,結構體的概念就像是一道曙光,為我們提供了一個非常有力的工具。 結
👨‍💻簡介 當我們在寫程式時,有時候會需要在程式結束時關閉某些資源,而defer這個關鍵字,可以讓你輕鬆的實現,下面來簡單介紹一下defer以及常用的範例。,它為程式設計師提供了一種簡單而強大的工具,用於管理資源和確保程式的正確執行。
👨‍💻簡介 在Go中,假如我要判斷一個資料類型是甚麼,該怎麼做呢? Golang有一個功能叫做Type Assertions(類型斷言),它的作用就是能夠在運行時檢查我的資料類型,讓我在傳遞類型時能確保資料類型是正確的。
👨‍💻簡介 make函數在slice、map和之後會介紹到的channel的初始化中扮演著關鍵的角色。本文將會簡單介紹make函數的用法,以及在初始化不同資料結構時的差異,讓你更好地理解和利用make函數。
👨‍💻簡介 套件(Package)在Golang中扮演著組織和管理程式碼的重要角色。 package就像工具箱一樣,裡面裝滿各種不同的工具,每個工具都有特定的功能。這些工具能夠幫助你完成不同的任務,從修理家具到蓋小屋,樣樣都行。
👨‍💻簡介 在Go語言中,Interface 是一個重要且強大的概念。Interface提供了一種方式來定義對象之間的契約,讓你可以設計更具有靈活性和可擴展性的程式碼。 你可以把Interface想像成是一種約定,讓不同的東西彼此溝通的方式變得特別靈活和好擴充,告訴程式裡的各個元件彼此要怎麼合作
👨‍💻簡介 在程式開發的世界中,我們經常需要處理各式各樣的資料,可能是一個人的個人資訊,也可能是一個商品的詳細訊息。當我們面對這麼多的資料時,如何將它們有系統地整理起來,讓我們能夠輕鬆地找到所需,便成了一個重要的課題。這時,結構體的概念就像是一道曙光,為我們提供了一個非常有力的工具。 結
你可能也想看
Google News 追蹤
Thumbnail
*合作聲明與警語: 本文係由國泰世華銀行邀稿。 證券服務係由國泰世華銀行辦理共同行銷證券經紀開戶業務,定期定額(股)服務由國泰綜合證券提供。   剛出社會的時候,很常在各種 Podcast 或 YouTube 甚至是在朋友間聊天,都會聽到各種市場動態、理財話題,像是:聯準會降息或是近期哪些科
Thumbnail
在今年1月19日,日本的甲府地方法院對被告遠藤裕喜判決死刑,判決當天,各大媒體爭相報導,因為這是在日本少年法修法後,第一件對「特定少年」做出的死刑判決[1],這名少年後續撤回上訴,成為日本第一宗「特定少年」死刑確定的案件[2]。這位被告遠藤裕喜,是對同班的女同學求愛不成,便前往對方的家中刺殺其父母,
Thumbnail
在進行程式設計時,錯誤與異常是無法避免的一部分,理解這些錯誤和異常的處理機制,對於程式設計師來說非常重要。本文將介紹 Python 中的錯誤與異常,以及如何有效使用 try-except 語句來處理這些不可預期的狀況。
Thumbnail
當我們談論 Web 應用開發時,錯誤處理和日誌記錄是兩個相對容易被忽視,但卻非常重要的環節。在本文中,我們將探索如何在 Gin Web 框架中實現這兩項功能。
Thumbnail
學習軟體開發的路上常常苦於網路資訊爆炸嗎? 教學何其多,但卻遇到無法明確選擇的困境呢? 歡迎加入「🔒 阿Han的軟體心法實戰營」, 這裡不給您冗餘的雜訊, 單刀直入直接送您業界開發重點, 避開選擇障礙的困境, 讓您獲得業界標準的開發起手式, 成為Top 1的頂尖人才。 人生的道路中總會來點意外與
Thumbnail
👨‍💻簡介 在軟體開發中,錯誤無所不在。無論是網路請求失敗、檔案不存在,還是數學計算錯誤,處理錯誤是任何開發者的日常工作,系統的穩定度基本取決於對於錯誤處理是否全面,好的錯誤處理也可以產生適當的錯誤訊息,讓 Debug 更加容易。
Thumbnail
在程式設計中,錯誤處理是一個不可或缺的部分。C#提供了強大的錯誤處理機制,讓我們能夠更有效地管理和處理程式執行中可能出現的問題。本篇文章將帶你深入了解如何在C#中捕捉與處理錯誤,確保你的程式在遇到問題時能夠優雅地回應。
Thumbnail
職場上常常會發現,計算薪資時,為什麼EXCEL計算的薪水跟我用計算機按出來的不一樣😱 很典型的例子2+2為什麼EXCEL顯示3呢? 其實99.9999%原因會出在四捨五入 如果說儲存格格式設定為0,代表儲存格僅會顯示到整數位數,如果數值是1.5時就會顯示2,但其實他的內容還是1.5哦,所以看起
Thumbnail
本篇文章介紹了在Python中的錯誤處理機制。錯誤處理在程式設計中是一個重要環節,能夠有效處理可能發生的錯誤。示範了如何捕捉錯誤並根據不同錯誤類型進行處理或提示。此外,還介紹了指定特定錯誤類型和捕捉所有錯誤的方法。透過學習這些錯誤處理的技巧,讀者可以更好地避免程式崩潰,提供友善的使用者體驗。
Thumbnail
新北市私幼餵藥案話題持續延燒,許多民眾在新北市政府市民廣場參加「不藥傷孩」活動,約八百名家長帶著孩子參加,高喊要求新北市政府揭露真相。 藥物對孩童的影響程度,這可是個讓人疑惑的議題。畢竟,孩子們的身體和心智正處於發展階段,藥物的使用是否會對他們的成長造成長遠的影響呢?
Thumbnail
Solidity語言的錯誤檢查提供了Require()、Revert()、Assert(),這三種方便的API調用,而這三種用途分別不同,畢竟牽涉到瓦斯費的問題,因此才會與過往的程式語言有些許的差異, require()通常會被使用在輸入值的驗證檢查,因為它的特性主要是能夠退回剩餘的Gas fee,
Thumbnail
*合作聲明與警語: 本文係由國泰世華銀行邀稿。 證券服務係由國泰世華銀行辦理共同行銷證券經紀開戶業務,定期定額(股)服務由國泰綜合證券提供。   剛出社會的時候,很常在各種 Podcast 或 YouTube 甚至是在朋友間聊天,都會聽到各種市場動態、理財話題,像是:聯準會降息或是近期哪些科
Thumbnail
在今年1月19日,日本的甲府地方法院對被告遠藤裕喜判決死刑,判決當天,各大媒體爭相報導,因為這是在日本少年法修法後,第一件對「特定少年」做出的死刑判決[1],這名少年後續撤回上訴,成為日本第一宗「特定少年」死刑確定的案件[2]。這位被告遠藤裕喜,是對同班的女同學求愛不成,便前往對方的家中刺殺其父母,
Thumbnail
在進行程式設計時,錯誤與異常是無法避免的一部分,理解這些錯誤和異常的處理機制,對於程式設計師來說非常重要。本文將介紹 Python 中的錯誤與異常,以及如何有效使用 try-except 語句來處理這些不可預期的狀況。
Thumbnail
當我們談論 Web 應用開發時,錯誤處理和日誌記錄是兩個相對容易被忽視,但卻非常重要的環節。在本文中,我們將探索如何在 Gin Web 框架中實現這兩項功能。
Thumbnail
學習軟體開發的路上常常苦於網路資訊爆炸嗎? 教學何其多,但卻遇到無法明確選擇的困境呢? 歡迎加入「🔒 阿Han的軟體心法實戰營」, 這裡不給您冗餘的雜訊, 單刀直入直接送您業界開發重點, 避開選擇障礙的困境, 讓您獲得業界標準的開發起手式, 成為Top 1的頂尖人才。 人生的道路中總會來點意外與
Thumbnail
👨‍💻簡介 在軟體開發中,錯誤無所不在。無論是網路請求失敗、檔案不存在,還是數學計算錯誤,處理錯誤是任何開發者的日常工作,系統的穩定度基本取決於對於錯誤處理是否全面,好的錯誤處理也可以產生適當的錯誤訊息,讓 Debug 更加容易。
Thumbnail
在程式設計中,錯誤處理是一個不可或缺的部分。C#提供了強大的錯誤處理機制,讓我們能夠更有效地管理和處理程式執行中可能出現的問題。本篇文章將帶你深入了解如何在C#中捕捉與處理錯誤,確保你的程式在遇到問題時能夠優雅地回應。
Thumbnail
職場上常常會發現,計算薪資時,為什麼EXCEL計算的薪水跟我用計算機按出來的不一樣😱 很典型的例子2+2為什麼EXCEL顯示3呢? 其實99.9999%原因會出在四捨五入 如果說儲存格格式設定為0,代表儲存格僅會顯示到整數位數,如果數值是1.5時就會顯示2,但其實他的內容還是1.5哦,所以看起
Thumbnail
本篇文章介紹了在Python中的錯誤處理機制。錯誤處理在程式設計中是一個重要環節,能夠有效處理可能發生的錯誤。示範了如何捕捉錯誤並根據不同錯誤類型進行處理或提示。此外,還介紹了指定特定錯誤類型和捕捉所有錯誤的方法。透過學習這些錯誤處理的技巧,讀者可以更好地避免程式崩潰,提供友善的使用者體驗。
Thumbnail
新北市私幼餵藥案話題持續延燒,許多民眾在新北市政府市民廣場參加「不藥傷孩」活動,約八百名家長帶著孩子參加,高喊要求新北市政府揭露真相。 藥物對孩童的影響程度,這可是個讓人疑惑的議題。畢竟,孩子們的身體和心智正處於發展階段,藥物的使用是否會對他們的成長造成長遠的影響呢?
Thumbnail
Solidity語言的錯誤檢查提供了Require()、Revert()、Assert(),這三種方便的API調用,而這三種用途分別不同,畢竟牽涉到瓦斯費的問題,因此才會與過往的程式語言有些許的差異, require()通常會被使用在輸入值的驗證檢查,因為它的特性主要是能夠退回剩餘的Gas fee,