安稳顺利毕业:6款2026年顶尖AI论文软件深度测评
2026/6/1 0:17:27
错误处理是Go语言编程中非常重要的一部分。本文将深入探讨Go语言的错误处理机制和最佳实践。
type error interface { Error() string } func New(text string) error { return &errorString{text} } type errorString struct { s string } func (e *errorString) Error() string { return e.s }func divide(a, b float64) (float64, error) { if b == 0 { return 0, fmt.Errorf("division by zero") } return a / b, nil } func main() { result, err := divide(10, 0) if err != nil { fmt.Println("Error:", err) return } fmt.Println("Result:", result) }type MyError struct { Code int Message string } func (e *MyError) Error() string { return fmt.Sprintf("Error %d: %s", e.Code, e.Message) } func process(input string) error { if input == "" { return &MyError{Code: 1001, Message: "empty input"} } return nil }// 模式1:直接返回错误 func doSomething() error { err := step1() if err != nil { return err } err = step2() if err != nil { return err } return step3() } // 模式2:提前返回 func processFile(path string) error { file, err := os.Open(path) if err != nil { return fmt.Errorf("failed to open file: %w", err) } defer file.Close() data, err := io.ReadAll(file) if err != nil { return fmt.Errorf("failed to read file: %w", err) } return processData(data) }func fetchData(url string) error { resp, err := http.Get(url) if err != nil { return fmt.Errorf("http request failed: %w", err) } defer resp.Body.Close() if resp.StatusCode != http.StatusOK { return fmt.Errorf("unexpected status code: %d", resp.StatusCode) } return nil } func main() { err := fetchData("http://example.com") if err != nil { fmt.Printf("Error: %v\n", err) var urlErr *url.Error if errors.As(err, &urlErr) { fmt.Printf("URL error: %v\n", urlErr.URL) } } }func isTimeoutError(err error) bool { var timeoutErr interface{ Timeout() bool } return errors.As(err, &timeoutErr) && timeoutErr.Timeout() } func isNotFoundError(err error) bool { return errors.Is(err, os.ErrNotExist) } func main() { err := doSomething() if isTimeoutError(err) { fmt.Println("Operation timed out") } else if isNotFoundError(err) { fmt.Println("Resource not found") } else if err != nil { fmt.Printf("Unexpected error: %v\n", err) } }type ValidationError struct { Field string Message string } func (e *ValidationError) Error() string { return fmt.Sprintf("validation error on field '%s': %s", e.Field, e.Message) } func (e *ValidationError) Is(target error) bool { _, ok := target.(*ValidationError) return ok } type DatabaseError struct { Query string Err error } func (e *DatabaseError) Error() string { return fmt.Sprintf("database error on query '%s': %v", e.Query, e.Err) } func (e *DatabaseError) Unwrap() error { return e.Err }func validateUser(user User) error { if user.Name == "" { return &ValidationError{Field: "Name", Message: "name cannot be empty"} } if user.Email == "" { return &ValidationError{Field: "Email", Message: "email cannot be empty"} } if user.Age < 18 { return &ValidationError{Field: "Age", Message: "must be at least 18"} } return nil } func saveUser(user User) error { err := validateUser(user) if err != nil { return fmt.Errorf("validation failed: %w", err) } query := fmt.Sprintf("INSERT INTO users VALUES ('%s', '%s', %d)", user.Name, user.Email, user.Age) _, err = db.Exec(query) if err != nil { return &DatabaseError{Query: query, Err: err} } return nil }// 不好的做法:忽略错误 func badExample() { file, _ := os.Open("data.txt") // 忽略错误 defer file.Close() data, _ := io.ReadAll(file) // 忽略错误 fmt.Println(string(data)) } // 好的做法:处理错误 func goodExample() error { file, err := os.Open("data.txt") if err != nil { return fmt.Errorf("failed to open file: %w", err) } defer file.Close() data, err := io.ReadAll(file) if err != nil { return fmt.Errorf("failed to read file: %w", err) } fmt.Println(string(data)) return nil }// 不好的做法:模糊的错误信息 func badError() error { return errors.New("something went wrong") } // 好的做法:具体的错误信息 func goodError() error { return fmt.Errorf("failed to connect to database at %s: %w", "localhost:5432", connectionErr) }func doWork() error { err := fetchData() if err != nil { return fmt.Errorf("work failed: %w", err) } return nil } func fetchData() error { err := makeRequest() if err != nil { return fmt.Errorf("fetch failed: %w", err) } return nil } func makeRequest() error { return fmt.Errorf("network error") } func main() { err := doWork() fmt.Println(err) // work failed: fetch failed: network error }func processRequest(req Request) error { err := validateRequest(req) if err != nil { log.Printf("Validation failed for request %s: %v", req.ID, err) return err } err = executeRequest(req) if err != nil { log.Printf("Execution failed for request %s: %v", req.ID, err) return fmt.Errorf("request execution failed: %w", err) } return nil }func main() { defer func() { if r := recover(); r != nil { log.Printf("Recovered from panic: %v", r) } }() process() } func process() { data := getData() if data == nil { panic("data is nil") } // 继续处理... }// 可以使用panic的场景 func init() { config, err := loadConfig() if err != nil { panic(fmt.Sprintf("failed to load config: %v", err)) } appConfig = config } // 不应该使用panic的场景 func getUser(id string) (User, error) { user, err := db.GetUser(id) if err != nil { return User{}, fmt.Errorf("failed to get user: %w", err) // 返回错误,不要panic } return user, nil }var ( ErrNotFound = errors.New("not found") ErrTimeout = errors.New("timeout") ErrInvalid = errors.New("invalid input") ) func findUser(id string) (User, error) { user, ok := users[id] if !ok { return User{}, ErrNotFound } return user, nil } func main() { user, err := findUser("123") if err == ErrNotFound { fmt.Println("User not found") } else if err != nil { fmt.Printf("Unexpected error: %v\n", err) } }func handleError(err error) { var validationErr *ValidationError var dbErr *DatabaseError switch { case errors.As(err, &validationErr): fmt.Printf("Validation error: %s\n", validationErr.Field) case errors.As(err, &dbErr): fmt.Printf("Database error: %s\n", dbErr.Query) default: fmt.Printf("Unknown error: %v\n", err) } }type MultiError struct { errors []error } func (e *MultiError) Add(err error) { e.errors = append(e.errors, err) } func (e *MultiError) Error() string { var sb strings.Builder sb.WriteString("multiple errors: ") for i, err := range e.errors { if i > 0 { sb.WriteString("; ") } sb.WriteString(err.Error()) } return sb.String() } func (e *MultiError) HasErrors() bool { return len(e.errors) > 0 } func validateForm(form Form) error { var me MultiError if form.Name == "" { me.Add(&ValidationError{Field: "Name", Message: "cannot be empty"}) } if form.Email == "" { me.Add(&ValidationError{Field: "Email", Message: "cannot be empty"}) } if form.Password == "" { me.Add(&ValidationError{Field: "Password", Message: "cannot be empty"}) } if me.HasErrors() { return &me } return nil }Go语言的错误处理机制强调显式处理:
掌握这些技巧可以编写出健壮、可维护的错误处理代码。