吾八哥博客

您现在的位置是:首页 > 码农手记 > 正文

码农手记

吾八哥学Golang(十):Golang里的错误处理

吾八哥2018-02-18码农手记1929

错误处理是程序开发过程中一个很常见的动作,正确的处理程序的错误将会极大的提升问题故障排查的效率。Go语言通过内置的错误接口提供了非常简单的错误处理机制,下面简单的介绍相关的方法。

内置error包

error包定义

go里内置的error接口定义如下:

type error interface {
	Error() string
}

errors包里的定义:

package errors

// New returns an error that formats as the given text.
// Each call to New returns a distinct error value even if the text is identical.
func New(text string) error {
	return &errorString{text}
}

// errorString is a trivial implementation of error.
type errorString struct {
	s string
}

func (e *errorString) Error() string {
	return e.s
}

定义非常简单,就是通过Error方法返回一个错误的string描述信息。

error使用方法

error通常用于某函数方法返回错误,而且大家都习惯的作为最后一个参数返回,下面看个简单使用例子:

package main

import (
	"errors"
	"fmt"
)

func foo1(num int) error {
	if num >= 100 {
		return errors.New("只能传小于100的数字")
	}
	return nil
}

func main() {
	if err := foo1(1024); err != nil {
		fmt.Println(err)
		return
	}
}

上面的函数用于判断传入的参数是否小于100,大于或等于100的时候就返回错误,返回的error错误可以使用fmt.Println进行打印出来。

自定义error类型

基于error类型的接口定义简单,我们也可以很方便的进行自定义error类型,只需要自定义类型里实现Error方法即可,下面的是自定义error实现方法以及用法:

package main

import (
	"fmt"
)

type MyError struct {
	Num int
	Msg string
}

func (e *MyError) Error() string {
	return fmt.Sprintf("Num:%d, Msg: %s", e.Num, e.Msg)
}

func foo1(num int) error {
	if num >= 100 {
		return &MyError{
			Num: num,
			Msg: "只能传小于100的数字",
		}
	}
	return nil
}

func main() {
	if err := foo1(1024); err != nil {
		fmt.Println(err)
		return
	}
}

开源error包

内置的error包能处理一些简单的错误信息,往往在复杂的代码逻辑处理过程中,简单的错误信息不便于排除问题,比较多的开源的error包已经具备了这样的能力,例如:github.com/pkg/errors,该包具备输出堆栈的信息,有如下几个关键方法:

// 新生成一个带堆栈信息的错误
func New(message string) error

// 附加信息
func WithMessage(err error, message string) error

// 附加调用堆栈信息
func WithStack(err error) error

// 同时附加堆栈和信息
func Wrap(err error, message string) error

这里使用Wrap方法来演示一个使用的例子:

package main

import (
	"fmt"
	"io/ioutil"

	"github.com/pkg/errors"
)

func foo1() (string, error) {
	data, err := ioutil.ReadFile("test.data")
	if err != nil {
		return "", errors.Wrap(err, "读取文件失败")
	}
	return string(data), nil
}

func main() {
	str, err := foo1()
	if err != nil {
		fmt.Printf("%+v", err)
		return
	}
	fmt.Println(str)
}

这里请注意,要打印出堆栈信息必须使用%+v,具体的区别为:

%s,%v  输出错误信息但不包含堆栈
%q     输出的错误信息带引号但不包含堆栈
%+v    输出错误信息和堆栈

上面的例子里返回的错误信息为:

image.png