SoFunction
Updated on 2025-03-05

Detailed explanation of how Go error is used

Overview

When we need to design an error in a Go project, we have to first know several commonly used methods of Go error. The standard library is a very good way to learn, and in addition, the errors feature of Go1.13 also needs to be mastered.

How to use error

1. Direct judgment

The judgments here are divided into variable judgments and type judgments.
It is suitable for predefined multiple error variables or types in pkg, and err may only be one of these variables.
Case: (err)

// Variable judgment etc.var errObj = (errObj)
func IsErrObj(err error) bool {
    return err == errObj
}
// Type judgment etc.type PathError struct {
   Op   string
   Path string
   Err  error
}
func IsPathError(err error) bool {
    switch e := err.(type) {
    case *PathError:
        return true
    default:
        return false
    }
} 

2. Combine the error interface to build a more powerful error interface

Suitable for constructing error interface types dedicated to pkg level, and combining Err variables in struct to indicate underlying errors
Case: interface

package net
type Error interface {
   error
   Timeout() bool   // Is the error a timeout?
   Temporary() bool // Is the error temporary?
}

type AddrError struct {
   Err  string
   Addr string
}

model

We know that Linux has a large number of error codes, indicating various error types, and error codes are very useful for many systems. How is Go compatible with this errono mode?
Case:

type Errno uintptr
func (e Errno) Error() string {
   if 0 <= int(e) && int(e) < len(errors) {
      s := errors[e]
      if s != "" {
         return s
      }
   }
   return "errno " + (int(e))
}

4. Go1.13's Wrap mode

In some scenarios, errors have chain relationships. Although we can implement a chain error type ourselves, Go1.13 introduces language-level support. It's very simple, with only 3 important uses:

// Create an errorerr2 := ("%w", err1)
// Determine whether an error chain contains an err variableok := (err2, err1) // true
// Determine whether the error chain can be assigned to a certain err type. If it succeeds, it will be assigned to the targettype Errno int
func (e *Errno) Error() string {
   return (int(*e))
}

func test() {
    var no = Errno(1)
    no1 := ("%w", &amp;no)
    no2 := ("%w", no1)
    
    var target *Errno
    ok := (no2, target)
    (ok, target) // true, 1
}

All the above codes depend on functions, which parses out the previous error of the chained error through reflection.
As can be seen from the code, it is used to determine whether the former links the latter when we have 2 err variables;
For us, we have an error variable and an error type. We want to determine whether the chain contains this error type. If so, we save the value in the target, which is equivalent to discarding some chain information and returning to the originality. Here are 2 notes:

  • Unwrap depends on reflection. We know that Go's reflection is very slow, so we need to use it with caution in scenarios that consider performance.
  • As function uses yes, the target itself must be the pointer type of struct and the address must be taken, otherwise it may be panic.

5. Chain error when Go version is low

Sometimes we will see the /pkg/errors package. It is actually the package referenced by the old version of Go that wants to use chain error. Its commonly used methods are Wrap and Cause. So when you see these two functions, you can guess that a project does not use the new errors feature.

This is the article about how to use Go error. For more information about using Go error, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!