|
|
@@ -0,0 +1,79 @@
|
|
|
+# 16.10 糟糕的错误处理
|
|
|
+
|
|
|
+依附于[第13章](13.0.md)模式的描述和[第17.1小节](17.1.md)与[第17.2.4小节](17.2.md)的总结。
|
|
|
+
|
|
|
+- 16.10.1 不要使用布尔值:
|
|
|
+
|
|
|
+像下面代码一样,创建一个布尔型变量用于测试错误条件是多余的:
|
|
|
+
|
|
|
+```go
|
|
|
+var good bool
|
|
|
+ // 测试一个错误,`good`被赋为`true`或者`false`
|
|
|
+ if !good {
|
|
|
+ return errors.New("things aren’t good")
|
|
|
+ }
|
|
|
+```
|
|
|
+
|
|
|
+立即检测一个错误:
|
|
|
+
|
|
|
+```go
|
|
|
+... err1 := api.Func1()
|
|
|
+if err1 != nil { … }
|
|
|
+```
|
|
|
+
|
|
|
+- 16.10.2 避免错误检测使代码变得混乱:
|
|
|
+
|
|
|
+避免写出这样的代码:
|
|
|
+
|
|
|
+```go
|
|
|
+... err1 := api.Func1()
|
|
|
+if err1 != nil {
|
|
|
+ fmt.Println(“err: “ + err.Error())
|
|
|
+ return
|
|
|
+}
|
|
|
+err2 := api.Func2()
|
|
|
+if err2 != nil {
|
|
|
+...
|
|
|
+ return
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+首先,包括在一个初始化的`if`语句中对函数的调用。
|
|
|
+
|
|
|
+但即使代码中到处都是以`if`语句的形式通知错误(通过打印错误信息)。通过这种方式,很难分别什么是正常的程序逻辑,什么是错误检测或错误通知。还需注意的是,大部分代码都是致力于错误的检测。通常解决此问题的好办法是尽可能以闭包的形式封装你的错误检测,例如下面的代码:
|
|
|
+
|
|
|
+```go
|
|
|
+
|
|
|
+func httpRequestHandler(w http.ResponseWriter, req *http.Request) {
|
|
|
+ err := func () error {
|
|
|
+ if req.Method != "GET" {
|
|
|
+ return errors.New("expected GET")
|
|
|
+ }
|
|
|
+ if input := parseInput(req); input != "command" {
|
|
|
+ return errors.New("malformed command")
|
|
|
+ }
|
|
|
+ // 可以在此进行其他的错误检测
|
|
|
+ } ()
|
|
|
+
|
|
|
+ if err != nil {
|
|
|
+ w.WriteHeader(400)
|
|
|
+ io.WriteString(w, err)
|
|
|
+ return
|
|
|
+ }
|
|
|
+ doSomething() ...
|
|
|
+```
|
|
|
+
|
|
|
+这种方法清晰的区别了错误检测、错误通知和正常的程序逻辑(更详细的方式参考[第13.5小节](13.5.md))。
|
|
|
+
|
|
|
+**在开始阅读[第17章](17.0.md)前,先回答下列2个问题:**
|
|
|
+
|
|
|
+ - 问题 16.1:总结你能记住的所有关于`,ok`模式的情况。
|
|
|
+
|
|
|
+ - 问题 16.2:总结你能记住的所有关于`defer`模式的情况。
|
|
|
+
|
|
|
+
|
|
|
+## 链接
|
|
|
+
|
|
|
+- [目录](directory.md)
|
|
|
+- 上一节:[闭包和协程的使用](16.9.md)
|
|
|
+- 下一章:[模式](17.0.md)
|