在线观看www成人影院-在线观看www日本免费网站-在线观看www视频-在线观看操-欧美18在线-欧美1级

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

閉包在錯誤處理中的應用模式探索

馬哥Linux運維 ? 來源:華為云社區 ? 2024-03-15 09:57 ? 次閱讀

錯誤

通過在函數和方法中返回錯誤對象作為它們的唯一或最后一個返回值——如果返回 nil,則沒有錯誤發生——并且主調(calling)函數總是應該檢查收到的錯誤。

處理錯誤并且在函數發生錯誤的地方給用戶返回錯誤信息:照這樣處理就算真的出了問題,你的程序也能繼續運行并且通知給用戶。panic and recover 是用來處理真正的異常
庫函數通常必須返回某種錯誤提示給主調(calling)函數。

為了防止發生錯誤時正在執行的函數(如果有必要的話甚至會是整個程序)被中止,在調用函數后必須檢查錯誤。

if value, err := pack1.Func1(param1); err != nil {
fmt.Printf(“Error %s in pack1.Func1 with parameter %v”, err.Error(), param1)
return // or: return err
}
// Process(value)

錯誤處理

Go 有一個預先定義的 error 接口類型

type error interface {
Error() string
}

錯誤值用來表示異常狀態;

程序處于錯誤狀態時可以用 os.Exit(1) 來中止運行。

定義錯誤

任何時候當你需要一個新的錯誤類型,都可以用 errors (必須先 import)包的errors.New 函數接收合適的錯誤信息來創建,像下面這樣:err := errors.New(“math - square root of negative number”)在下面中你可以看到一個簡單的用例:

// errors.go
package main
import (
"errors"
"fmt"
)
var errNotFound error = errors.New("Not found error")
func main() {
fmt.Printf("error: %v", errNotFound)
}
// error: Not found error

可以把它用于計算平方根函數的參數測試:

func Sqrt(f float64) (float64, error) {
if f < 0 {
return 0, errors.New (“math - square root of negative number”)
}
// implementation of Sqrt
}

你可以像下面這樣調用 Sqrt 函數:

if f, err := Sqrt(-1); err != nil {
fmt.Printf(“Error: %s
”, err)
}
```## 用 fmt 創建錯誤對象
通常你想要返回包含錯誤參數的更有信息量的字符串,例如:可以用 fmt.Errorf() 來實現:它和fmt.Printf() 完全一樣,接收有一個或多個格式占位符的格式化字符串和相應數量的占位變量。和打印信息不同的是它用信息生成錯誤對象。
比如在前面的平方根例子中使用:
```go
if f < 0 {
return 0, fmt.Errorf(“math: square root of negative number %g”, f)
}

第二個例子:從命令行讀取輸入時,如果加了 help 標志,我們可以用有用的信息產生一個錯誤:

if len(os.Args) > 1 && (os.Args[1] == “-h” || os.Args[1] == “--help”) {
err = fmt.Errorf(“usage: %s infile.txt outfile.txt”, filepath.Base(os.Args[0]))
return
}

運行時異常和 panic

當發生像數組下標越界或類型斷言失敗這樣的運行錯誤時,Go 運行時會觸發運行時 panic,伴隨著程序的崩潰拋出一個 runtime.Error 接口類型的值。這個錯誤值有個 RuntimeError() 方法用于區別普通錯誤。

panic 可以直接從代碼初始化:當錯誤條件(我們所測試的代碼)很嚴苛且不可恢復,程序不能繼續運行時,可以使用 panic 函數產生一個中止程序的運行時錯誤。panic 接收一個做任意類型的參數,通常是字符串,在程序死亡時被打印出來。Go 運行時負責中止程序并給出調試信息。

package main
import "fmt"
func main() {
fmt.Println("Starting the program")
panic("A severe error occurred: stopping the program!")
fmt.Println("Ending the program")
}

輸出如下:

Starting the program
panic: A severe error occurred: stopping the program!
panic PC=0x4f3038
runtime.panic+0x99 /go/src/pkg/runtime/proc.c:1032
runtime.panic(0x442938, 0x4f08e8)
main.main+0xa5 E:/Go/GoBoek/code examples/chapter 13/panic.go:8
main.main()
runtime.mainstart+0xf 386/asm.s:84
runtime.mainstart()
runtime.goexit /go/src/pkg/runtime/proc.c:148
runtime.goexit()
---- Error run E:/Go/GoBoek/code examples/chapter 13/panic.exe with code Crashed
---- Program exited with code -1073741783

一個檢查程序是否被已知用戶啟動的具體例子:

var user = os.Getenv(“USER”)
func check() {
if user == “” {
panic(“Unknown user: no value for $USER”)
}
}

可以在導入包的 init() 函數中檢查這些。

當發生錯誤必須中止程序時, panic 可以用于錯誤處理模式:

if err != nil {
panic(“ERROR occurred:” + err.Error())
}

Go panicking:

在多層嵌套的函數調用中調用 panic,可以馬上中止當前函數的執行,所有的 defer 語句都會保證執行并把控制權交還給接收到 panic 的函數調用者。這樣向上冒泡直到最頂層,并執行(每層的) defer,在棧頂處程序崩潰,并在命令行中用傳給 panic 的值報告錯誤情況:這個終止過程就是 panicking。

從 panic 中恢復(Recover)

正如名字一樣,這個(recover)內建函數被用于從 panic 或 錯誤場景中恢復:讓程序可以從 panicking重新獲得控制權,停止終止過程進而恢復正常執行。

recover 只能在 defer 修飾的函數中使用:用于取得 panic 調用中傳遞過來的錯誤值,如果是正常執行,調用 recover 會返回 nil,且沒有其它效果。

總結:panic 會導致棧被展開直到 defer 修飾的 recover() 被調用或者程序中止。下面例子中的 protect 函數調用函數參數 g 來保護調用者防止從 g 中拋出的運行時 panic,并展示 panic中的信息:

func protect(g func()) {
defer func() {
log.Println(“done”)
// Println executes normally even if there is a panic
if err := recover(); err != nil {
log.Printf(“run time panic: %v”, err)
}
}()
log.Println(“start”)
g() // possible runtime-error
}

log 包實現了簡單的日志功能:默認的 log 對象向標準錯誤輸出中寫入并打印每條日志信息的日期和時間。除了 Println 和 Printf 函數,其它的致命性函數都會在寫完日志信息后調用 os.Exit(1),那些退出函數也是如此。而 Panic 效果的函數會在寫完日志信息后調用 panic;可以在程序必須中止或發生了臨界錯誤時使用它們.下面展示 panic,defer 和 recover 怎么結合使用的完整例子:

// panic_recover.go
package main
import (
"fmt"
)
func badCall() {
panic("bad end")
}
func test() {
defer func() {
if e := recover(); e != nil {
fmt.Printf("Panicing %s
", e)
}
}()
badCall()
fmt.Printf("After bad call
") // <-- wordt niet bereikt
}
func main() {
fmt.Printf("Calling test
")
test()
fmt.Printf("Test completed
")
}

輸出:

Calling test
Panicing bad end
Test completed

defer-panic-recover 在某種意義上也是一種像 if , for 這樣的控制流機制。

自定義包中的錯誤處理和 panicking

這是所有自定義包實現者應該遵守的最佳實踐:
1)在包內部,總是應該從 panic 中 recover:不允許顯式的超出包范圍的 panic()。
2)向包的調用者返回錯誤值(而不是 panic)。
在包內部,特別是在非導出函數中有很深層次的嵌套調用時,對主調函數來說用 panic 來表示應該被翻譯成錯誤的錯誤場景是很有用的。

// parse.go
package parse
import (
"fmt"
"strings"
"strconv"
)
// ParseError 表示將單詞轉換為整數時出錯。
type ParseError struct {
Index int // 以空格分隔的單詞列表的索引。
Word string // 生成分析錯誤的單詞。
Err error // 引發此錯誤的原始錯誤(如果有)。
}
// 
func (e *ParseError) String() string {
return fmt.Sprintf("pkg parse: error parsing %q as int", e.Word)
}
// Parse 將 put 中以空格分隔的單詞解析為整數。
func Parse(input string) (numbers []int, err error) {
defer func() {
if r := recover(); r != nil {
var ok bool
err, ok = r.(error)
if !ok {
err = fmt.Errorf("pkg: %v", r)
}
}
}()
fields := strings.Fields(input)
numbers = fields2numbers(fields)
return
}
func fields2numbers(fields []string) (numbers []int) {
if len(fields) == 0 {
panic("no words to parse")
}
for idx, field := range fields {
num, err := strconv.Atoi(field)
if err != nil {
panic(&ParseError{idx, field, err})
}
numbers = append(numbers, num)
}
return
}
// panic_package.go
package main
import (
"fmt"
"./parse/parse"
)
func main() {
var examples = []string{
"1 2 3 4 5",
"100 50 25 12.5 6.25",
"2 + 2 = 4",
"1st class",
"",
}
for _, ex := range examples {
fmt.Printf("Parsing %q:
 ", ex)
nums, err := parse.Parse(ex)
if err != nil {
fmt.Println(err) 
continue
}
fmt.Println(nums)
}
}

輸出:

Parsing “1 2 3 4 5”:
[1 2 3 4 5]
Parsing “100 50 25 12.5 6.25”:
pkg parse: error parsing “12.5” as int
Parsing “2 + 2 = 4”:
pkg parse: error parsing “+” as int
Parsing “1st class”:
pkg parse: error parsing “1st” as int
Parsing “”:
pkg: no words to parse

一種用閉包處理錯誤的模式

每當函數返回時,我們應該檢查是否有錯誤發生:但是這會導致重復乏味的代碼。結合
defer/panic/recover 機制和閉包可以得到一個我們馬上要討論的更加優雅的模式。不過這個模式只有當所有的函數都是同一種簽名時可用,這樣就有相當大的限制。一個很好的使用它的例子是 web 應用,所有的處理函數都是下面這樣:

func handler1(w http.ResponseWriter, r *http.Request) { ... }

假設所有的函數都有這樣的簽名:

func f(a type1, b type2)

參數的數量和類型是不相關的。

我們給這個類型一個名字:

fType1 = func f(a type1, b type2)

在我們的模式中使用了兩個幫助函數:

1)check:這是用來檢查是否有錯誤和 panic 發生的函數:func check(err error) { if err != nil { panic(err) } }

2)errorhandler:這是一個包裝函數。接收一個 fType1 類型的函數 fn 并返回一個調用 fn 的函數。里面就包含有 defer/recover 機制。

func errorHandler(fn fType1) fType1 {
return func(a type1, b type2) {
defer func() {
if e, ok := recover().(error); ok {
log.Printf(“run time panic: %v”, err)
}
}()
fn(a, b)
}
}

當錯誤發生時會 recover 并打印在日志中;除了簡單的打印,應用也可以用 template 包為用戶生成自定義的輸出。check() 函數會在所有的被調函數中調用,像這樣:

func f1(a type1, b type2) {
...
f, _, err := // call function/method
check(err)
t, err := // call function/method
check(err)
_, err2 := // call function/method
check(err2)
...
}

通過這種機制,所有的錯誤都會被 recover,并且調用函數后的錯誤檢查代碼也被簡化為調用 check(err)即可。在這種模式下,不同的錯誤處理必須對應不同的函數類型;

審核編輯:黃飛

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 程序
    +關注

    關注

    117

    文章

    3817

    瀏覽量

    82208
  • 函數
    +關注

    關注

    3

    文章

    4365

    瀏覽量

    63908
  • Printf
    +關注

    關注

    0

    文章

    83

    瀏覽量

    14029

原文標題:一種用閉包處理錯誤的模式

文章出處:【微信號:magedu-Linux,微信公眾號:馬哥Linux運維】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏

    評論

    相關推薦
    熱點推薦

    嵌入式編程錯誤處理機制設計

    本文主要總結嵌入式系統C語言編程,主要的錯誤處理方式。文中涉及的代碼運行環境如下。
    發表于 04-28 09:59 ?896次閱讀
    嵌入式編程<b class='flag-5'>錯誤處理</b>機制設計

    嵌入式系統C語言編程主要的錯誤處理方式

    本文主要總結嵌入式系統C語言編程,主要的錯誤處理方式。
    發表于 07-24 16:40 ?1135次閱讀
    嵌入式系統C語言編程<b class='flag-5'>中</b>主要的<b class='flag-5'>錯誤處理</b>方式

    Rust語言中錯誤處理的機制

    可能的錯誤,實際運行仍然可能出現各種各樣的錯誤,比如文件不存在、網絡連接失敗等等。對于這些不可預測的錯誤,我們必須使用錯誤處理機制來進行
    的頭像 發表于 09-19 14:54 ?1713次閱讀

    嵌入式C編程常用的異常錯誤處理

    嵌入式C編程,異常錯誤處理是確保系統穩定性和可靠性的重要部分。以下是一些常見的異常錯誤處理方法及其詳細說明和示例: 1. 斷言 (Assertions) 斷言用于在開發階段捕獲程序
    發表于 08-06 14:32

    labviEW錯誤處理的問題

    為什么這個程序在啟用自動錯誤處理和C:\data.txt不存在的情況下,沒有顯示錯誤對話框啊?
    發表于 04-01 10:03

    LabVIEW錯誤處理問題

    我想問一下,就是連接硬件采集波形時,需要濾掉直流波,但是采集到的波形時斷斷續續的,所以錯誤處理時會停止程序,我想問一下,運行時怎么忽略掉這個錯誤
    發表于 09-18 18:29

    AF錯誤處理

    想問一下關于AF的錯誤處理,例如我進行串口通訊,打開串口錯誤,但是我不想停止AF,想繼續嘗試連接要怎么做?
    發表于 02-03 15:44

    LabVIEW錯誤處理

    如何合理使用 LabVIEW 的自定義錯誤處理功能;對于可預見的錯誤,是否可以選擇直 接忽略,或者前幾次嘗試忽略直到該特定錯誤出現很多次后才通知用戶需要糾正該
    發表于 05-24 11:07 ?6次下載

    Spring Boot框架錯誤處理

    》 《strong》翻譯《/strong》:雁驚寒《/p》 《/blockquote》《p》《em》摘要:本文通過實例介紹了使用Spring Boot在設計API的時候如何正確地對異常進行處理。以下是譯文《/em》《/p》《p》API在提供錯誤消息的同時進行適當的
    發表于 09-28 15:31 ?0次下載

    嵌入式系統C語言編程錯誤處理資料總結

    本文主要總結嵌入式系統C語言編程,主要的錯誤處理方式。文中涉及的代碼運行環境如下:
    發表于 11-28 10:39 ?2051次閱讀

    Rust代碼啟發之返回值異常錯誤處理

    這樣的代碼,錯誤處理代碼和業務邏輯交織在一起,也容易忽略處理錯誤。以及把返回值只用于錯誤返回,有點浪費的感覺。因為很多時候把計算結果作為返回值,更符合思考的邏輯。
    的頭像 發表于 09-22 09:24 ?2370次閱讀
    Rust代碼啟發之返回值異常<b class='flag-5'>錯誤處理</b>

    RS232通信時怎么處理錯誤?RS232通信中的錯誤處理方法

    RS232通信時怎么處理錯誤?RS232通信中的錯誤處理方法? RS232通信是一種電氣標準,它定義了計算機和串行通信設備之間的通信協議。盡管RS232通信很穩定,但仍然可能會出現錯誤
    的頭像 發表于 10-17 16:33 ?3524次閱讀

    西門子博圖:錯誤處理機制概覽

    可通過以下幾種不同的錯誤處理機制進行參數跟蹤或編程或訪問錯誤
    的頭像 發表于 11-25 11:35 ?3648次閱讀
    西門子博圖:<b class='flag-5'>錯誤處理</b>機制概覽

    C語言中的錯誤處理機制解析

    C 語言不提供對錯誤處理的直接支持,但是作為一種系統編程語言,它以返回值的形式允許您訪問底層數據。
    的頭像 發表于 02-26 11:19 ?664次閱讀

    socket編程錯誤處理技巧

    Socket編程是網絡編程的基礎,它允許程序之間通過TCP/IP協議進行通信。然而,網絡通信是不穩定的,可能會遇到各種問題,如網絡延遲、連接中斷、數據丟失等。 錯誤處理的重要性 提高程序的健壯性
    的頭像 發表于 11-01 17:47 ?1331次閱讀
    主站蜘蛛池模板: 激情综合站 | 淫五月| gay超刺激污文 | 久久女人网 | 国产成人高清一区二区私人 | 欧美日韩亚洲一区 | 男女做视频网站免费观看 | 久久久久久久久久免免费精品 | 色婷婷激情综合 | 久热国产在线 | 色天使色护士 在线视频观看 | 高清在线免费观看 | 色综合天天综合给合国产 | 韩国精品视频 | 日本系列 1页 亚洲系列 | 亚洲精品视频专区 | 又粗又硬又猛又黄的免费视频黑人 | 国产精品久久久久乳精品爆 | 亚洲专区一区 | 中文字幕卡二和卡三的视频 | 男男h文小说阅 | 免费在线看片网站 | sihu影院永久在线影院 | 最刺激黄a大片免费观看下截 | 中文字幕有码在线视频 | 亚洲午夜久久久精品影院 | 黄色片网站观看 | 美女黄页网 | 色综合天天射 | 国产在线视频你懂得 | 色老头网站久久网 | 日韩一级片在线免费观看 | 性色在线视频精品 | 婷婷亚洲综合一区二区 | 狠狠色96视频 | 亚洲成在人天堂一区二区 | 成年1314在线观看 | 欧美色图亚洲综合 | 久草视频一区 | 国产午夜免费 | 国产h视频在线观看 |