error处理

go1.13之前的错误处理

错误检查
if err != nil {
    //something wrong...
}

有时我们将错误与已知的前哨值(sentinel value)进行比较来查看是否发生了特定错误。

var permissionError = errors.New("permission deny")

if err == permissionError {
    //permission deny
}

错误值可以是满足语言定义的error接口的任何类型。
程序可以使用类型断言来判断错误值是否可被视为特定的错误类型。

type NotFoundError struct {
    Name string
}

func (err *NotFoundError) Error() string {
    return err.Name + ":not found"
}

if e, ok := err.(*NotFoundError); ok {
    //e.Name wasn't found
}
添加信息

一种简单的方法是构造一个新错误,并在其中包括上一个错误。

if err != nil {
    return fmt.Errorf("decompress %v: %v", name, err)
}

使用fmt.Errorf创建的新错误将丢弃原始错误中的所有内容(文本除外)。

package main

import "fmt"

type NotFoundError struct {
    Name string
}

func (err *NotFoundError) Error() string {
    return err.Name + ":not found"
}

func main() {
    err1 := &NotFoundError{"user"}
    //err1已经变成了string,user:not found,原始错误中的所有内容都丢失了
    err2 := fmt.Errorf("db err:%v", err1)
    //db err:user:not found
    fmt.Println(err2)
}

有时我们可能想要定义一个包含基础错误的新错误类型,并将其保存下来以供代码检查。

type QueryError struct {
    Query string
    Err   error
}

func (e *QueryError) Error() string {
    return e.Query + ": " + e.Err.Error()
}

程序可以查看一个*QueryError值的内部以根据潜在的错误进行决策。

var ErrNotFound = errors.New("not found")

if e, ok := err.(*QueryError); ok && e.Err == ErrNotFound {
    // query failed because of a not found error
}

go1.13之后的错误处理

一个约定

在go 1.13中,最重要的不是改变,而是一个约定:
包含另一个错误的错误可以实现Unwrap方法来返回所包含的底层错误。
如果e1.Unwrap()返回了e2,那么我们说e1包装了e2,您可以Unwrap e1来得到e2。

用%w包装错误

在go 1.13中,fmt.Errorf函数支持新的%w动词。
当存在该动词时,被封装的原始错误不会丢失,可用于errors.Is和errors.As。

封装与Is、As
package main

import (
    "fmt"
    "github.com/pkg/errors"
)

type NotFound struct {
    Name string
}

func (err *NotFound) Error() string {
    return err.Name + " not found"
}

type RepoError struct {
    Err error
}

func (err *RepoError) Error() string {
    return "repo error:" + err.Err.Error()
}

func (err *RepoError) Unwrap() error {
    return err.Err
}

func main() {

    userNotFound := &NotFound{"user"}
    userRepoError := &RepoError{userNotFound}
    middlewareErr := fmt.Errorf("middleware:%w", userRepoError)

    shopNotFound := &NotFound{"shop"}

    //Is reports whether any error in err's chain matches target.
    fmt.Println(errors.Is(middlewareErr, userNotFound))  //true
    fmt.Println(errors.Is(middlewareErr, userRepoError)) //true
    fmt.Println(errors.Is(middlewareErr, shopNotFound))  //false,errors.Is函数将错误与值进行比较

    userNotFoundTarget := &NotFound{}
    userRepoErrorTarget := &RepoError{}

    //As finds the first error in err's chain that matches target, and if one is found, sets target to that error value and returns true.
    fmt.Println(errors.As(middlewareErr, &userNotFoundTarget)) //true,As函数用于测试错误是否为特定类型
    fmt.Println(userNotFoundTarget)                            //user not found

    fmt.Println(errors.As(middlewareErr, &userRepoErrorTarget)) //true
    fmt.Println(userRepoErrorTarget)                            //repo error:user not found

}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,651评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,468评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,931评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,218评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,234评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,198评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,084评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,926评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,341评论 1 311
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,563评论 2 333
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,731评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,430评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,036评论 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,676评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,829评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,743评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,629评论 2 354

推荐阅读更多精彩内容

  • 在Go中,对于处理错误一般分为两种情况: 错误和异常. 在Go中,错误的处理一般都是通过 error接口来指定;异...
    张哈阅读 1,698评论 0 2
  • 背景介绍 如果你有写过Go代码,那么你可以会遇到Go中内建类型error。Go语言使用error值来显示异常状态。...
    陈奇天阅读 2,492评论 0 6
  • error 与 try catch 对比 有人说if err写得繁琐,而我却觉得更直接/直白,好处就是维护性更好,...
    bysir阅读 12,988评论 2 8
  • 错误处理 Go语言的错误设计是通过返回值的方式来让调用者对错误进行处理,通常我们的处理是对error类型的返回值进...
    Carrism阅读 2,581评论 0 0
  • 错误处理(异常处理) 错误类型 开发过程中常见的错误: 语法错误(编译报错) 逻辑错误 (偏离开发人员本意) 运行...
    爱玩游戏的iOS菜鸟阅读 223评论 0 0