『Go 内置库第一季:error』

大家好,我叫谢伟,是一名程序员。

近期我会持续更新内置库的学习笔记,主要参考的是文档 godoc 和 内置库的源码

本节的主题:error

Go 中的错误处理和别的语言不一样,设计哲学也不一样,常有开发者埋怨 Go 语言中的错误处理。

本节从内置库的 error 出发,结合内置库的常用的 错误处理手法,总结出适合项目的错误处理方式。

大纲

  • 自己的常用的 error 错误处理方式
  • 内置库实现的 error
  • 总结

自己的总结常用的 error 错误处理方式

1. 创建 error 类型的值

  • errors.New()
  • fmt.Errorf()

这两个方法即可实现。

package main

import (
    "errors"
    "fmt"
    "reflect"
)

func main() {

    recordError := errors.New("record not found")
    dbError := fmt.Errorf("%s", "db connet fail")
    fmt.Println(recordError, reflect.TypeOf(recordError))
    fmt.Println(dbError, reflect.TypeOf(dbError))

}
>>
record not found *errors.errorString
db connet fail *errors.errorString

2. 自定义错误类型

  • 实现 error 接口
type CodeError struct {
    Code    int
    Message string
}

func (c CodeError) Error() string {
    return fmt.Sprintf(" e.Code = %d, e.Message=%s", c.Code, c.Message)
}

func Result() error {
    var codeError CodeError
    codeError = CodeError{
        Code:    400,
        Message: "connect fail",
    }
    return codeError
}

func main(){
    
    var codeError CodeError
    var err error
    codeError = CodeError{
        Code:    404,
        Message: "http status code error",
    }
    err = codeError
    fmt.Println(err)
}
>>
e.Code = 404, e.Message=http status code error

自己定义的错误类型,只要实现了 error 接口即可。

可以看下具体的 接口定义:

type error interface {
    Error() string
}
  • errors.New 的具体实现
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
}

即 定义了 errorString 结构体, 绑定了 Error 方法

  • fmt.Errorf 的具体实现
func Errorf(format string, a ...interface{}) error {
    return errors.New(Sprintf(format, a...))
}

即 fmt.Errorf 调用的也是 errors.New 方法。

总结上文:

  1. 创建 error 存在两种方法
  2. 底层 是一个结构体实现了 error 接口
  3. 自定义的错误类型,实现 Error 方法即可

内置库实现的 error

错误很常见,是业务的一部分,那么内置的库在实现时也会遇到错误,看内置库是如何实现的 error

1. strconv.Atoi

func main(){
    
    number, err := strconv.Atoi("2992-121")
    fmt.Println(number,err)
}
>>
0 strconv.Atoi: parsing "2992-121": invalid syntax

具体的底层实现是:

type NumError struct {
    Func string // the failing function (ParseBool, ParseInt, ParseUint, ParseFloat)
    Num  string // the input
    Err  error  // the reason the conversion failed (e.g. ErrRange, ErrSyntax, etc.)
}

func (e *NumError) Error() string {
    return "strconv." + e.Func + ": " + "parsing " + Quote(e.Num) + ": " + e.Err.Error()
}

定义各种错误类型:

var ErrRange = errors.New("value out of range")
var ErrSyntax = errors.New("invalid syntax")
func syntaxError(fn, str string) *NumError {
    return &NumError{fn, str, ErrSyntax}
}

func rangeError(fn, str string) *NumError {
    return &NumError{fn, str, ErrRange}
}

func baseError(fn, str string, base int) *NumError {
    return &NumError{fn, str, errors.New("invalid base " + Itoa(base))}
}

func bitSizeError(fn, str string, bitSize int) *NumError {
    return &NumError{fn, str, errors.New("invalid bit size " + Itoa(bitSize))}
}

即:核心是定义了一个结构体,实现了 error 接口

2. net/http

func main(){
    
    response, err := http.Get("https://space.bilibili.com/10056291/#/")
    fmt.Println(response, err)
    
}

底层的错误类型是:

type Error struct {
    Op  string
    URL string
    Err error
}

func (e *Error) Error() string { return e.Op + " " + e.URL + ": " + e.Err.Error() }

即定义了一个结构体,实现的 error 接口。

鉴于对内置库的底层的 错误类型的阅读,修改自己设置错误类型的方法:如下

type ExampleError struct {
    Err     error
    Code    int
    Message string
}

func (e *ExampleError) Error() string {
    return fmt.Sprintf("e.Code = %d e.Err = %s e.Message = %s", e.Code, e.Err.Error(), e.Message)
}

func ExampleResult() error {
    return &ExampleError{
        Err:     errors.New("what the fucking life"),
        Code:    502,
        Message: "what the fucking life",
    }
}

总结

  • 创建 error 值存在两种方法
  • 自己定义的错误类型,只需实现 Error 方法,实现 error 接口即可

其他:对错误的处理还有这些建议

  • 每个库,可以在库文件的开头声明常见的错误
var ErrorIndexOut = errors.New("index out of range")
var ErrorFuck = errors.New("fucking life")
  • 错误类型的变量可以带上 Err 或者 Error 标示
  • 建议统一处理错误类型,即,完整的项目在声明自己的库处理模块,而不是随意的在项目内创建 error

<完>

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏cnblogs

knockoutjs 上自己实现的flux

在knockoutjs 上实现 Flux 单向数据流 状态机,主要解决多个组件之间对数据的耦合问题。 一、其实简单 flux的设计理念和实现方案,很大程度上人借...

2208
来自专栏自由而无用的灵魂的碎碎念

Tips in Visual Studio 2008

.NET几乎程序员都在使用visual studio 2008进行开发。可是,你通过它达到最大的开发效率了吗?

1232
来自专栏DOTNET

学会WCF之试错法——客户端调用基础

1当客户端调用未返回结果时,服务不可用(网络连接中断,服务关闭,服务崩溃等) 客户端抛出异常 异常类型:CommunicationException Inne...

2798
来自专栏软件开发

前端MVC Vue2学习总结(七)——ES6与Module模块化、Vue-cli脚手架搭建、开发、发布项目与综合示例

使用vue-cli可以规范项目,提高开发效率,但是使用vue-cli时需要一些ECMAScript6的知识,特别是ES6中的模块管理内容,本章先介绍ES6中的基...

4477
来自专栏ccylovehs

JavaScript异步编程

平时开发经常会用到js异步编程,由于前端展示页面都是基于网络机顶盒(IPTV的一般性能不太好,OTT较好),目前公司主要采取的异步编程的方式有setTimeou...

1352
来自专栏一枝花算不算浪漫

[Java拾遗四]JavaWeb基础之Servlet_Request&&Response

3718
来自专栏游戏杂谈

C# StreamReader.ReadLine统计行数的问题

从 lua 文件中提取字符串放到 excel 中,再将 excel 给海外同事,翻译完成后,用翻译的文本替换相应中文。

911
来自专栏图像识别与深度学习

《HTML5实战》Lesson10

Week11  2016/11/23上午1-4节 一、复习 ? 对应的html ? 二、execCommand实现富文本编辑控件 1、execCommand ...

3475
来自专栏葡萄城控件技术团队

程序员级别鉴定书(.NET面试问答集锦)

作为一个.NET程序员,应该知道的不仅仅是拖拽一个控件到设计时窗口中。就像一个赛车手,一定要了解他的爱车 – 能做什么不能做什么。 本文参考Scott Hans...

3757
来自专栏DOTNET

.NET MongoDB Driver GridFS 2.2原理及使用示例

一、API解读 1 GridFSBucketOptions 1)public string BucketName { get; set; } 获取或设置buck...

3478

扫码关注云+社区

领取腾讯云代金券