程序员求职经验分享与学习资料整理平台

网站首页 > 文章精选 正文

Go语言零到一:错误处理(go 错误处理)

balukai 2025-07-14 14:50:11 文章精选 3 ℃

引言

错误处理是软件工程中的一个重要方面,它直接影响到程序的健壮性和用户体验。Go 语言采用了一种不同于传统异常处理的错误处理机制,鼓励开发者显式地处理错误而不是依赖于异常。


1. 错误处理原则

  • 显式错误处理
    • Go 鼓励在函数中返回一个 error 类型的值,以便调用者可以检查和处理错误。
    • 示例:
func readFile(filename string) ([]byte, error) {
	file, err := os.Open(filename)
	if err != nil {
		return nil, err
	}
	defer file.Close()

	data, err := ioutil.ReadAll(file)
	if err != nil {
		return nil, err
	}
	return data, nil
}
  • 不要忽视错误
    • 应该始终检查并处理函数返回的错误,避免让错误无声无息地消失。
    • 示例:
data, err := readFile("example.txt") 
if err != nil { 
 log.Fatal(err) 
}
  • 使用 log.Fatallog.Panic
    • 当遇到无法恢复的错误时,可以使用 log.Fatallog.Panic 来记录错误并终止程序。
    • 示例:
if err != nil { 
 log.Fatal(err) 
}
  • 避免错误的不当传播
    • 在函数中遇到错误时,应尽快处理或向上层传播,避免错误被忽略或延迟处理。
    • 示例:
func processFile(filename string) error { 
 data, err := readFile(filename) 
 if err != nil { 
 return err 
 } 
 // 处理 data 
 return nil 
}
  • 使用 panicrecover
    • panic 用于标记不可恢复的错误,导致当前 goroutine 停止执行。
    • recover 可以在一个 defer 函数中使用,用于捕获和处理由 panic 引发的错误。
    • 示例:
func safeDivide(x, y int) int { 
 defer func() { 
 if r := recover(); r != nil { 
 fmt.Println("Recovered in safeDivide", r) 
 } 
 }() 
 return x / y 
}

2. 错误类型和错误链

  • 自定义错误类型
    • 可以定义自己的错误类型,以便更精确地描述错误的性质。
    • 示例:
type FileNotFoundError struct { 
 Filename string 
} 
 
func (e *FileNotFoundError) Error() string { 
 return fmt.Sprintf("file %s not found", e.Filename) 
}
  • 错误链
    • 可以使用 errors.Wraperrors.Cause 函数来创建错误链,这有助于追踪错误的根源。
    • 示例:
func readFile(filename string) ([]byte, error) { 
 file, err := os.Open(filename) 
 if err != nil { 
 return nil, errors.Wrap(err, "failed to open file") 
 } 
 defer file.Close() 
 
 data, err := ioutil.ReadAll(file) 
 if err != nil { 
 return nil, errors.Wrap(err, "failed to read file") 
 } 
 
 return data, nil 
}

3. 实践出真知,动手写一下吧

package main

import (
  "fmt"
  "io/ioutil"
  "log"
  "os"
  "strconv"
  "strings"

  "github.com/pkg/errors"
)

func readFile(filename string) ([]byte, error) {
  file, err := os.Open(filename)
  if err != nil {
    return nil, errors.Wrap(err, "failed to open file")
  }
  defer file.Close()

  data, err := ioutil.ReadAll(file)
  if err != nil {
    return nil, errors.Wrap(err, "failed to read file")
  }
  return data, nil
}

func parseData(data []byte) (int, error) {
  strData := strings.TrimSpace(string(data))
  value, err := strconv.Atoi(strData)
  if err != nil {
    return 0, errors.Wrap(err, "failed to parse data")
  }
  return value, nil
}

func main() {
  filename := "example.txt"
  data, err := readFile(filename)
  if err != nil {
    log.Fatal(err)
  }

  value, err := parseData(data)
  if err != nil {
    log.Fatal(err)
  }

  fmt.Println("Parsed value:", value)
}

Tags:

最近发表
标签列表