diff --git a/eBook/13.4.md b/eBook/13.4.md index a9f53e4..e7eb6c2 100644 --- a/eBook/13.4.md +++ b/eBook/13.4.md @@ -1,2 +1,126 @@ -# 自定义包中的错误处理和 panicking +# 13.4 自定义包中的错误处理和 panicking +这是所有自定义包实现者应该遵守的最佳实践: + +1)*在包内部,总是应该从 panic 中 recover*:不允许显式的超出包范围的 panic() + +2)*向包的调用者返回错误值(而不是 panic)。* + +在包内部,特别是在非导出函数中有很深层次的嵌套调用时,对主调函数来说用 panic 来表示应该被翻译成错误的错误场景是很有用的(并且提高了代码可读性)。 + +这在下面的代码中被很好地阐述了。我们有一个简单的 parse 包(示例 13.4)用来把输入的字符串解析为整数切片;这个包有自己特殊的 `ParseError`。 + +当没有东西需要转换或者转换成整数失败时,这个包会 panic(在函数 fields2numbers 中)。但是可导出的 Parse 函数会从 panic 中 recover 并用所有这些信息返回一个错误给调用者。为了演示这个过程,在 panic_recover.go 中 调用了 parse 包(示例 13.4);不可解析的字符串会导致错误并被打印出来。 + +示例 13.4 [parse.go](examples/chapter_13/parse/parse.go): + +```go +// parse.go +package parse + +import ( + "fmt" + "strings" + "strconv" +) + +// A ParseError indicates an error in converting a word into an integer. +type ParseError struct { + Index int // The index into the space-separated list of words. + Word string // The word that generated the parse error. + Err error // The raw error that precipitated this error, if any. +} + +// String returns a human-readable error message. +func (e *ParseError) String() string { + return fmt.Sprintf("pkg parse: error parsing %q as int", e.Word) +} + +// Parse parses the space-separated words in in put as integers. +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 +} + +``` + +示例 13.5 [panic_package.go](examples/chapter_13/panic_package.go): + +```go +// 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:\n ", ex) + nums, err := parse.Parse(ex) + if err != nil { + fmt.Println(err) // here String() method from ParseError is used + 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 + +``` + + +## 链接 + +- [目录](directory.md) +- 上一节:[从 panic 中恢复 (Recover)](13.3.md) +- 下一节:[一种用闭包处理错误的模式](13.5.md) diff --git a/eBook/13.5.md b/eBook/13.5.md new file mode 100644 index 0000000..a1d6831 --- /dev/null +++ b/eBook/13.5.md @@ -0,0 +1,2 @@ +# 13.5 一种用闭包处理错误的模式 + diff --git a/eBook/directory.md b/eBook/directory.md index 061ea76..91fabef 100644 --- a/eBook/directory.md +++ b/eBook/directory.md @@ -129,6 +129,7 @@ - 13.2 [运行时异常和 panic](13.2.md) - 13.3 [从 panic 中恢复 (Recover)](13.3.md) - 13.4 [自定义包中的错误处理和 panicking](13.4.md) + - 13.5 [一种用闭包处理错误的模式](13.5.md) - 第14章:goroutine 与 channel - 第15章:网络、模版与网页应用