Go 语言入门很简单:Go 语言的错误处理(上)

简介: 文将介绍 Go 中的错误处理,以及为什么我们需要错误处理。

什么是错误处理

异常处理是任何语言都不能绕不开的话题。Go 语言没有提供传统的 try...catch 语句来处理异常,而是通过使用 error 来处理错误,用 panicrecover 来处理异常。


错误封装是将一个错误包裹到另一个错误的过程。假设我们有一个访问数据库的 Web 服务器,并试图从数据库中获取一条记录。如果数据库调用返回一个错误,我们可以决定是捕获这个错误还是从网络服务中发送我们自己的自定义错误。

基础 error

error 接口


error 是一种内建的接口类型,内建意味着不需要 import 任何包就可以直接使用,使用起来就像基础类型一样自然。

type error interface {
    Error() string
}


error 接口只声明了一个 Error() 方法,任何实现了该方法的结构体都可以作为 error 来使用。


  • error 的实例代表一种异常状态
  • Error() 方法用于描述该异常状态
  • 值为 nil 的 error 代表没有异常


标准库 errors 包中的 errorString 就是实现 error 接口的一个例子:

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


创建 error


标准库提供了两种 error 的方法:


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


  1. error.New()  的实现极其简单,只是简单地构造一个 errorString 实例便返回:
package errors
func New(text string) error {
    return &errorString{text}
}


  1. fmt.Errorf()


error.New() 单调地接收一个字符串参数来构造 error,而实际场景中往往需要使用 fmt.Sprintf()  生成字符串,这时可以直接使用 fmt.Errorf()

package fmt
func Errorf(format string, a ...interface{}) error {
    return errors.New(Sprintf(format,  a...))


联系与区别: fmt.Errorf() 只是对 error.New() 的简单封装,使用前者可以使得代码更加简洁。而两者的区别在于 fmt.Errorf() 适用于需要格式化输出错误字符串的场景,如果不需要格式化字符串,则建议使用  error.New()

异常处理

针对 error 而言,异常处理包括如何检查错误,如何传递错误。


  1. 检查 error


最常见的检查 error 的方式是与 nil 值进行比较:

if err != nil {
    // 错误处理逻辑
}


与预定义的 error 进行比较(可以是自定义也可以是标准库中的,比如 os 库中的常见错误):

var noRows = errors.New("no rows found")
if err == noRows {
}


  1. 传递 error


在一个函数中收到一个 error,往往需要附加一些上下文信息再把 error 继续向上层抛


可以看一下如下的例子:

package main
import (
  "errors"
  "fmt"
)
var noRows = errors.New("no rows found")
func getRecords() error {
  return noRows
}
func webService() error {
  if err := getRecords(); err != nil {
    return fmt.Errorf("Error %s when calling DB", err)
  }
  return nil
}
func main() {
  if err := webService(); err != nil {
    fmt.Printf("Error: %s when calling webService\n", err)
    return
  }
  fmt.Println("webService call successful")
}


运行结果:

$ go run .
Error: Error no rows found when calling DB when calling webService


在上面的程序中,我们在调用 getRecords 函数时,发送错误的字符串描述,虽然这可能看起来像错误处理,但实际上并不是。让我们接着看下去吧。

相关文章
|
1天前
|
安全 Java Go
探索Go语言在高并发环境中的优势
在当今的技术环境中,高并发处理能力成为评估编程语言性能的关键因素之一。Go语言(Golang),作为Google开发的一种编程语言,以其独特的并发处理模型和高效的性能赢得了广泛关注。本文将深入探讨Go语言在高并发环境中的优势,尤其是其goroutine和channel机制如何简化并发编程,提升系统的响应速度和稳定性。通过具体的案例分析和性能对比,本文揭示了Go语言在实际应用中的高效性,并为开发者在选择合适技术栈时提供参考。
|
5天前
|
运维 Kubernetes Go
"解锁K8s二开新姿势!client-go:你不可不知的Go语言神器,让Kubernetes集群管理如虎添翼,秒变运维大神!"
【8月更文挑战第14天】随着云原生技术的发展,Kubernetes (K8s) 成为容器编排的首选。client-go作为K8s的官方Go语言客户端库,通过封装RESTful API,使开发者能便捷地管理集群资源,如Pods和服务。本文介绍client-go基本概念、使用方法及自定义操作。涵盖ClientSet、DynamicClient等客户端实现,以及lister、informer等组件,通过示例展示如何列出集群中的所有Pods。client-go的强大功能助力高效开发和运维。
24 1
|
6天前
|
SQL 关系型数据库 MySQL
Go语言中使用 sqlx 来操作 MySQL
Go语言因其高效的性能和简洁的语法而受到开发者们的欢迎。在开发过程中,数据库操作不可或缺。虽然Go的标准库提供了`database/sql`包支持数据库操作,但使用起来稍显复杂。为此,`sqlx`应运而生,作为`database/sql`的扩展库,它简化了许多常见的数据库任务。本文介绍如何使用`sqlx`包操作MySQL数据库,包括安装所需的包、连接数据库、创建表、插入/查询/更新/删除数据等操作,并展示了如何利用命名参数来进一步简化代码。通过`sqlx`,开发者可以更加高效且简洁地完成数据库交互任务。
13 1
|
5天前
|
算法 NoSQL 中间件
go语言后端开发学习(六) ——基于雪花算法生成用户ID
本文介绍了分布式ID生成中的Snowflake(雪花)算法。为解决用户ID安全性与唯一性问题,Snowflake算法生成的ID具备全局唯一性、递增性、高可用性和高性能性等特点。64位ID由符号位(固定为0)、41位时间戳、10位标识位(含数据中心与机器ID)及12位序列号组成。面对ID重复风险,可通过预分配、动态或统一分配标识位解决。Go语言实现示例展示了如何使用第三方包`sonyflake`生成ID,确保不同节点产生的ID始终唯一。
go语言后端开发学习(六) ——基于雪花算法生成用户ID
|
7天前
|
JSON 缓存 监控
go语言后端开发学习(五)——如何在项目中使用Viper来配置环境
Viper 是一个强大的 Go 语言配置管理库,适用于各类应用,包括 Twelve-Factor Apps。相比仅支持 `.ini` 格式的 `go-ini`,Viper 支持更多配置格式如 JSON、TOML、YAML
go语言后端开发学习(五)——如何在项目中使用Viper来配置环境
|
1天前
|
监控 NoSQL Go
Go语言中高效使用Redis的Pipeline
Redis 是构建高性能应用时常用的内存数据库,通过其 Pipeline 和 Watch 机制可批量执行命令并确保数据安全性。Pipeline 类似于超市购物一次性结账,减少网络交互时间,提升效率。Go 语言示例展示了如何使用 Pipeline 和 Pipelined 方法简化代码,并通过 TxPipeline 保证操作原子性。Watch 机制则通过监控键变化实现乐观锁,防止并发问题导致的数据不一致。这些机制简化了开发流程,提高了应用程序的性能和可靠性。
5 0
|
3天前
|
NoSQL Go Redis
Go语言中如何扫描Redis中大量的key
在Redis中,遍历大量键时直接使用`KEYS`命令会导致性能瓶颈,因为它会一次性返回所有匹配的键,可能阻塞Redis并影响服务稳定性。为解决此问题,Redis提供了`SCAN`命令来分批迭代键,避免一次性加载过多数据。本文通过两个Go语言示例演示如何使用`SCAN`命令:第一个示例展示了基本的手动迭代方式;第二个示例则利用`Iterator`简化迭代过程。这两种方法均有效地避免了`KEYS`命令的性能问题,并提高了遍历Redis键的效率。
11 0
|
4天前
|
监控 Serverless Go
Golang 开发函数计算问题之Go 语言中切片扩容时需要拷贝原数组中的数据如何解决
Golang 开发函数计算问题之Go 语言中切片扩容时需要拷贝原数组中的数据如何解决
|
5天前
|
关系型数据库 MySQL 数据库连接
Go语言中使用sqlx来操作事务
在应用中,数据库事务保证操作的ACID特性至关重要。`github.com/jmoiron/sqlx`简化了数据库操作。首先安装SQLX和MySQL驱动:`go get github.com/jmoiron/sqlx`和`go get github.com/go-sql-driver/mysql`。导入所需的包后,创建数据库连接并使用`Beginx()`方法开始事务。通过`tx.Commit()`提交或`tx.Rollback()`回滚事务以确保数据一致性和完整性。
8 0
|
7天前
|
SQL 安全 关系型数据库
Go 语言中的 MySQL 事务操作
在现代应用中,确保数据完整与一致至关重要。MySQL的事务机制提供了可靠保障。本文首先解释了事务的概念及其ACID特性,随后介绍了如何在Go语言中使用`database/sql`包进行MySQL事务操作。通过一个银行转账的例子,演示了如何通过Go开启事务、执行操作并在必要时回滚或提交,确保数据一致性。最后,还讨论了不同事务隔离级别的含义及如何在Go中设置这些级别。通过本文的学习,开发者能更好地掌握MySQL事务的应用。
11 0