go 语言优雅地处理 error

这篇具有很好参考价值的文章主要介绍了go 语言优雅地处理 error。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

我看到很多 golang 社区的开发者,特别是因为它的简单性而被吸引的开发者,对 golang 中的事情应该如何处理做出了一些快速的判断。
其中一件事就是错误处理。由于目前大多数语言的开发者都来自于 OOP 背景,他们习惯于处理异常,或者说"抛出"异常的概念来停止当前的应用程序的流程,而且他们大多认为这也是 golang 的方式,我们必须在出错的情况下停止我们的应用程序的流程。他们错了!

不要滥用你的工具

我见过很多,我以前也是这样做的。每当有意外情况发生时,就用 os.exit(1),然后继续前进。好吧,这不是使用go的正确方法!
我明白为什么这被广泛使用,因为大多数早期的 golang 应用程序只是终端工具,而且许多这些工具曾经使用 .sh 可执行文件来构建,我们曾经只是退出1;以表示刚刚发生了一些意外的事情,我们想退出。
我们把这种习惯带到了我们的 golang 简单的终端应用中,然后又带到了复杂的应用中,这只是另一种 Cargo Cult Programming。
我高度鼓励你在不得不这样做的情况下,要非常小心,因为它是:

  • 随着你的应用程序的增长,非常难以维护。
  • 最重要的是,不可能对这样的代码进行单元测试,这显然表明它的不洁性。
  • 以这种方式退出将阻止你的任何延迟操作的执行,你的程序将立即终止,这可能导致资源泄漏。请考虑一下这个例子:
func main() {
    dbConnection := db.connect("...")
    defer dbConnection.Close() // this operation won't be executed!    
    entity := Entity{}
    err := dbConnection.Save(entity)
    if err != nil {
        os.Exit(1)
    }
}

考虑传递你的错误

错误只是 golang 中的另一种类型,你必须用它们来控制程序的执行流程。

为了做到这一点,我们必须在整个程序中传播这些错误,直到适当的处理点。

考虑一个管理订单的HTTP API,我们想禁止客户在特定条件下下订单,例如:

package order

// package errors
var (
    UnableToShipToCountry = errors.New("unable to ship order to the requested country")
)

type Order struct {
    // ... order fields
}

type OrderRepo struct {
    DB db
    // ...
}

func newOrderFromRequest(o OrderRequest) (Order, error) {
    if o.ShippingAddress.Country != "DE" {
	return UnableToShipToCountry
    }    // ... the creation logic
    return Order{...}, nil
}

func (r *OrderRepo)PlaceOrder(o OrderRequest) error {
    order, err := newOrderFromRequest(o)
    if err != nil {
        // don't handle the error here, its handling may differ
        return err
    }    // ... db transaction may also return an error
    return r.db.Save(order)
}

在我们的 http package 中:

package http

http.HandleFunc("/order", func (w http.ResponseWriter, r *http.Request) {
    orderRequest := createOrderRequest(r)
    err := orderRepo.PlaceOrder(orderRequest)
    if errors.Is(err, order.UnableToShipToCountry) {
        w.WriteHeader(http.StatusBadRequest)
        return
    }
    if err != nil {
        // this error in case of DB transaction failure
        w.WriteHeader(http.StatusInternalServerError)
        return
    }    // ...
    w.WriteHeader(http.StatusOK)
})

定制你的错误

我们可以创建我们自己的自定义错误值,并在我们的程序中使用它,同时考虑添加一些有用的信息,如错误跟踪这可能会给我们的日志增加一个有益的价值,特别是在调试期间。

type AppErr struct {  
    msg string  
    code int  
    trace string  
}  
  
func (e AppErr) Error() string {  
    return fmt.Sprintf("Msg: %s, code: %d, trace:\n %s", e.msg, e.code, e.trace)  
}  
  
func NewAppErr(msg string, code int) AppErr {  
    stackSlice := make([]byte, 512)  
    s := runtime.Stack(stackSlice, false)  
  
    return AppErr{msg, code, fmt.Sprintf("\n%s", stackSlice[0:s])}  
}

而我们在一个包内有这样一个用例:

package admin  
  
func A() error {  
    return b()  
}  
  
func b() error {  
    return NewAppErr("error from b function!", 3)  
}

main.go:

func main() {  
    err := admin.A()
    fmt.Println(err)
}

记录的错误信息将是:

Msg: error from b function!, code: 3, trace:  
  
goroutine 1 [running]:  
./cmd/app/error.NewAppErr({0x1f42b0, 0x17}, 0x7)  
./cmd/app/error/error.go:16 +0x35  
./cmd/app/admin.b(...)  
./cmd/app/admin/**admin.go:12**  
./cmd/app/admin.A(...)  
./cmd/app/admin/**admin.go:8**  
main.main()  
./cmd/app/**main.go:10** +0x8d

你也可以考虑在生产环境中关闭你的跟踪打印,或者通过检查其他配置值。文章来源地址https://www.toymoban.com/news/detail-801989.html

到了这里,关于go 语言优雅地处理 error的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • go-carbon v2.3.6 发布,轻量级、语义化、对开发者友好的 golang 时间处理库

    carbon 是一个轻量级、语义化、对开发者友好的 golang 时间处理库,支持链式调用。 目前已被 awesome-go 收录,如果您觉得不错,请给个 star 吧 github.com/golang-module/carbon gitee.com/golang-module/carbon 安装使用 Golang 版本大于等于 1.16 Golang 版本小于 1.16 更新日志 将日历提取出来作为独立

    2024年01月24日
    浏览(65)
  • go-carbon v2.3.5 发布,轻量级、语义化、对开发者友好的 golang 时间处理库

    carbon 是一个轻量级、语义化、对开发者友好的 golang 时间处理库,支持链式调用。 目前已被 awesome-go 收录,如果您觉得不错,请给个 star 吧 github.com/golang-module/carbon gitee.com/golang-module/carbon 安装使用 Golang 版本大于等于 1.16 Golang 版本小于 1.16 更新日志 Default 结构体新增 Locale

    2024年02月01日
    浏览(49)
  • go-carbon 2.2.12 版本发布, 轻量级、语义化、对开发者友好的 Golang 时间处理库

    carbon 是一个轻量级、语义化、对开发者友好的 golang 时间处理库,支持链式调用。 目前已被 awesome-go 收录,如果您觉得不错,请给个 star 吧 github.com/golang-module/carbon gitee.com/golang-module/carbon 安装使用 Golang 版本大于等于1.16 Golang 版本小于1.16 更新日志 增加对荷兰语的支持 测试

    2024年02月06日
    浏览(53)
  • 掌握Go语言:Go语言范围,优雅遍历数据结构,简化代码操作实战解析(24)

    在Go语言中,范围(range)用于迭代数组、切片、映射、通道等数据结构的元素。范围的语法形式为 for range ,可以遍历集合中的每个元素,并在每次迭代中返回元素的索引(或键)和对应的值。 Go语言范围使用方法 使用范围语句的一般形式为: 其中, index 是元素的索引(或

    2024年04月17日
    浏览(46)
  • Go语言热重载和优雅地关闭程序

    我们有时会因不同的目的去关闭服务,一种关闭服务是终止操作系统,一种关闭服务是用来更新配置。 我们希望优雅地关闭服务和通过热重载重新加载配置,而这两种方式可以通过信号包来完成。 首先,定义了一个 Config 结构并声明了一个 conf 变量。 这里的代码只是一个简

    2024年01月17日
    浏览(50)
  • Node.js与TypeScript:优雅的后端开发方式

    随着前端 JavaScript语言的不断发展, Node.js 开发环境也越来越受到开发者们的欢迎。 Node.js 让我们可以轻松地使用 JavaScript 来编写服务器端应用,从而实现前后端一致的开发体验。在 Node.js 的发展历程中, TypeScript 也逐渐成为了一种备受欢迎的编程语言,它的出现大大提高了

    2024年02月10日
    浏览(66)
  • 探索 Go 语言中 iota 的神奇力量,优雅定义常量!

    大家好!在今天的文章中,我将为大家介绍一下关于 golang 中的 iota 的使用技巧和注意事项。作为一种枚举常量生成器,iota 在 golang 中被广泛使用,可以简化代码和提高可读性。下面就让我们来了解一些关键的使用技巧和注意事项吧! 在 golang 中,iota 是一个预定义标识符,

    2024年02月13日
    浏览(41)
  • Golang | Web开发之Gin多服务配置及优雅关闭平滑重启

    欢迎关注「 全栈工程师修炼指南 」公众号 点击 👇  下方卡片  即可关注我哟! 设为 「 星标⭐ 」 每天带你  基础入门  到  进阶实践  再到  放弃学习 ! 专注  企业运维实践、网络安全、系统运维、应用开发、物联网实战、全栈文章  等知识分享 “    花开堪折直须折

    2024年02月08日
    浏览(43)
  • Go优雅的错误处理: 支持错误堆栈, 错误码, 错误链的工具库

    地址: https://github.com/morrisxyang/errors 如果觉得有用欢迎 Star 和 PR, 有问题请直接提issue 简单的支持 错误堆栈 , 错误码 , 错误链 的工具库: 支持携带堆栈, 嵌套构造错误链 支持携带错误码, 方便接口返回 支持自定义堆栈打印深度和错误链打印格式 使用 CallersFrames 替代 FuncForPC 生成

    2024年02月13日
    浏览(85)
  • Golang:Go语言结构

    在我们开始学习 Go 编程语言的基础构建模块前,让我们先来了解 Go 语言最简单程序的结构。 Go 语言的基础组成有以下几个部分: 包声明 引入包 函数 变量 语句 表达式 注释 接下来让我们来看下简单的代码,该代码输出了\\\"Hello World!\\\": 让我们来看下以上程序的各个部分: 第一

    2024年02月10日
    浏览(59)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包