概述

  • panic
    • 停止当前函数执行
    • 一直向上返回,执行每一层的defer
    • 如果没有遇到recover,程序退出
  • recover
    • 仅在defer调用中使用
    • 获取panic的值
    • 如果无法处理,可重新panic

代码

  1. package main
  2. import (
  3. "fmt"
  4. "os"
  5. "bufio"
  6. "golearn/functional/fib"
  7. )
  8. func tryDefer() {
  9. for i := 0; i < 100; i++ {
  10. defer fmt.Println(i)
  11. if i == 30 {
  12. // Uncomment panic to see
  13. // how it works with defer
  14. // panic("printed too many")
  15. }
  16. }
  17. }
  18. func writeFile(filename string) {
  19. file, err := os.OpenFile(filename,
  20. os.O_EXCL|os.O_CREATE|os.O_WRONLY, 0666)
  21. if err != nil {
  22. if pathError, ok := err.(*os.PathError); !ok {
  23. panic(err)
  24. } else {
  25. fmt.Printf("%s, %s, %s\n",
  26. pathError.Op,
  27. pathError.Path,
  28. pathError.Err)
  29. }
  30. return
  31. }
  32. defer file.Close()
  33. writer := bufio.NewWriter(file)
  34. defer writer.Flush()
  35. f := fib.Fibonacci()
  36. for i := 0; i < 20; i++ {
  37. fmt.Fprintln(writer, f())
  38. }
  39. }
  40. func main() {
  41. tryDefer()
  42. writeFile("fib.txt")
  43. }

分装错误处理

  1. package filelisting
  2. import (
  3. "fmt"
  4. "io/ioutil"
  5. "net/http"
  6. "os"
  7. "strings"
  8. )
  9. const prefix = "/list/"
  10. type userError string
  11. func (e userError) Error() string {
  12. return e.Message()
  13. }
  14. func (e userError) Message() string {
  15. return string(e)
  16. }
  17. func HandleFileList(writer http.ResponseWriter,
  18. request *http.Request) error {
  19. fmt.Println()
  20. if strings.Index(
  21. request.URL.Path, prefix) != 0 {
  22. return userError(
  23. fmt.Sprintf("path %s must start "+
  24. "with %s",
  25. request.URL.Path, prefix))
  26. }
  27. path := request.URL.Path[len(prefix):]
  28. file, err := os.Open(path)
  29. if err != nil {
  30. return err
  31. }
  32. defer file.Close()
  33. all, err := ioutil.ReadAll(file)
  34. if err != nil {
  35. return err
  36. }
  37. writer.Write(all)
  38. return nil
  39. }
  1. package main
  2. import (
  3. "log"
  4. "net/http"
  5. _ "net/http/pprof"
  6. "os"
  7. "golearn/errhandling/filelistingserver/filelisting"
  8. )
  9. type appHandler func(writer http.ResponseWriter,
  10. request *http.Request) error
  11. func errWrapper(
  12. handler appHandler) func(
  13. http.ResponseWriter, *http.Request) {
  14. return func(writer http.ResponseWriter,
  15. request *http.Request) {
  16. // panic
  17. defer func() {
  18. if r := recover(); r != nil {
  19. log.Printf("Panic: %v", r)
  20. http.Error(writer,
  21. http.StatusText(http.StatusInternalServerError),
  22. http.StatusInternalServerError)
  23. }
  24. }()
  25. err := handler(writer, request)
  26. if err != nil {
  27. log.Printf("Error occurred "+
  28. "handling request: %s",
  29. err.Error())
  30. // user error
  31. if userErr, ok := err.(userError); ok {
  32. http.Error(writer,
  33. userErr.Message(),
  34. http.StatusBadRequest)
  35. return
  36. }
  37. // system error
  38. code := http.StatusOK
  39. switch {
  40. case os.IsNotExist(err):
  41. code = http.StatusNotFound
  42. case os.IsPermission(err):
  43. code = http.StatusForbidden
  44. default:
  45. code = http.StatusInternalServerError
  46. }
  47. http.Error(writer,
  48. http.StatusText(code), code)
  49. }
  50. }
  51. }
  52. type userError interface {
  53. error
  54. Message() string
  55. }
  56. func main() {
  57. http.HandleFunc("/",
  58. errWrapper(filelisting.HandleFileList))
  59. err := http.ListenAndServe(":8888", nil)
  60. if err != nil {
  61. panic(err)
  62. }
  63. }

recover

  1. package main
  2. import (
  3. "fmt"
  4. )
  5. func tryRecover() {
  6. defer func() {
  7. r := recover()
  8. if r == nil {
  9. fmt.Println("Nothing to recover. " +
  10. "Please try uncomment errors " +
  11. "below.")
  12. return
  13. }
  14. if err, ok := r.(error); ok {
  15. fmt.Println("Error occurred:", err)
  16. } else {
  17. panic(fmt.Sprintf(
  18. "I don't know what to do: %v", r))
  19. }
  20. }()
  21. // Uncomment each block to see different panic
  22. // scenarios.
  23. // Normal error
  24. //panic(errors.New("this is an error"))
  25. // Division by zero
  26. //b := 0
  27. //a := 5 / b
  28. //fmt.Println(a)
  29. // Causes re-panic
  30. //panic(123)
  31. }
  32. func main() {
  33. tryRecover()
  34. }

image.jpeg