我的编程空间,编程开发者的网络收藏夹
学习永远不晚

golang 语言中错误处理机制

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

golang 语言中错误处理机制

与其他主流语言如 Javascript、Java 和 Python 相比,Golang 的错误处理方式可能和这些你熟悉的语言有所不同。所以才有了这个想法根大家聊一聊 golang 的错误处理方式,以及实际开发中应该如何对错误进行处理。因为分享面对 Golang有一个基本的了解 developers, 所以一些简单地方就不做赘述了。

如何定义错误

在 golang 语言中,无论是在类型检查还是编译过程中,都是将错误看做值来对待,和 string 或者 integer 这些类型值并不差别。声明一个 string 类型变量和声明一个 error 类型变量是没什么区别的。

你可以定义接口作为 error 的类型,有关 error 能够提供什么样信息都是由自己决定的,这是 error 在 golang 作为值的好处,不过这样做也自然有其坏处,有关 error 定义好坏就全由其定义开发人员所决定,也就是有关 error 融入过多人为的主观因素。


package main

import (
	"fmt"
	"io/ioutil"
)

func main(){
	dir, err := ioutil.TempDir("","temp")

	if err != nil{
		fmt.Errorf("failed to create temp dir: %v",err)
	}
}

错误在语言中的重点地位

在 Go 语言中错误处理设计一直大家喜欢讨论的内容,错误处理是该语言的核心,但该语言并没有规定如何处理错误。社区已经为改进和规范错误处理做出了努力,但许多人忽略了错误在我们应用程序领域中的核心地位。也就是说,错误与客户和订单类型一样重要。

Golang中的错误

错误表示在应用程序中发生了不需要的情况。比方说,想创建一个临时目录,在那里可以为应用程序存储一些文件,但这个目录的创建失败了。这是一个不期望的情况,就可以用错误来表示。

通过创建自定义错误可以将更丰富错误信息传递给调用者。个返回值返回将错误交给调用函数人来处理错误。Golang 本身允许函数具有多个返回值,所以通常把错误作为函数最后一个参数返回给调用者来处理。

errors 是 I/O

  • 有时候开发人员是 error 的生产者(写 error)
  • 有时候开发人员又是 error 的消费者(读 error)

也就是我们开发程序一部分工作是读取和写入 error

errors 的上下文
什么是 error 的上下文呢? 如何定义 error 需要考虑一些因素,例如在不同程序我们定义 error 和处理 error 方式也不仅相同

  1. CLI 工具
  2. 长时间运行的系统

而且我们需要考虑使用程序的人群,他们是什么方式来使用系统,这些因素都是我们设计也好定义错误信息要考虑的因素。

错误的类型

就错误核心,那么错误可能是我们预料之中的错误,错误也可能是我们没有考虑到,例如无效内存,数组越界,也就是单靠代码自身暂时是解决不了的错误 ,这样的误差往往让代码恐慌,所以 Panic。通常这样错误对于程序是灾难性的失败,无法修复的。

自定义错误

如前所述,错误使用内置的错误接口类型来表示,其定义如下。


type error interface {  
    Error() string
}

下面举了 2 例子来定义 error ,分别定义两个 struct 都实现了 Error() 接口即可


type SyntaxError struct {
    Line int
    Col  int
}

func (e *SyntaxError) Error() string {
    return fmt.Sprintf("%d:%d: syntax error", e.Line, e.Col)
}

type InternalError struct {
    Path string
}

func (e *InternalError) Error() string {
    return fmt.Sprintf("parse %v: internal error", e.Path)
}

该接口包含一个方法 Error() ,以字符串形式返回错误信息。每一个实现了错误接口的类型都可以作为一个错误使用。当使用 fmt.Println 等方法打印错误时,Golang 会自动调用 Error() 方法。

在 Golang 中,有多种创建自定义错误信息的方法,每一种都有自己的优点和缺点。

基于字符串的错误

基于字符串的错误可以用 Golang 中两个开箱即用方法来自定义错误,适用哪些仅返回描述错误信息的相对来说比较简单的错误。


err := errors.New("math: divided by zero")

将错误信息传入到 errors.New() 方法可以用来新建一个错误


err2 := fmt.Errorf("math: %g cannot be divided by zero", x)

fmt.Errorf 通过字符串格式方式,可以将错误信息包含你错误信息中。也就是为错误信息添加了一些格式化的功能。

自定义数据结构的错误

可以通过在你的结构上实现 Error 接口中定义的 Error() 函数来创建自定义的错误类型。下面是一个例子。

Defer, panic 和 recover

Go 并不像许多其他编程语言(包括 Java 和 Javascript )那样有异常,但有一个类似的机制,即 "Defer, panic 和 recover"。然而,panic 和 recover 的使用情况与其他编程语言中的异常非常不同,因为代码本身无法应对时候和不可恢复的情况下使用。

Defer

有点类似析构函数,在函数执行完毕后做一些资源释放等收尾工作,好处其执行和其在代码中位置并没有关系,所以可以将其写在你读写资源语句后面,以免随后忘记做一些资源释放的工作。关于 defer 输出也是面试时,面试官喜欢问的一个问题。


package main

import(
	"fmt"
	"os"
)

func main(){
	f := createFile("tmp/machinelearning.txt")
	defer closeFile(f)
	writeFile(f)
}

func createFile(p string) *os.File {
	fmt.Println("creating")
	f, err := os.Create(p)
	if err != nil{
		panic(err)
	}
	return f
}

func closeFile(f *os.File){
	fmt.Println("closing")
	err := f.Close()

	if err != nil{
		fmt.Fprintf(os.Stderr, "error:%v\n",err)
		os.Exit(1)
	}
}

func writeFile(f *os.File){
	fmt.Println("writing")
	fmt.Fprintln(f,"machine leanring")
}

defer 语句会将函数推入到一个栈结构中。同时栈结构中的函数会在 return 语句执行后被调用。


package main


import "fmt"

func main(){
	// defer fmt.Println("word")
	// fmt.Println("hello")

	fmt.Println("hello")
	for i := 0; i <=3; i++ {
		defer fmt.Println(i)
	}
	fmt.Println("world")
}

hello
world
3
2
1
0

可以通过在你的结构上实现 Error 接口中定义的 Error() 函数来实现自定义错误类型,下面是一个例子。

Panic

panic 语句向 Golang 发出信号,这时通常是代码无法解决当前的问题,所以停止代码的正常执行流程。一旦调用了 panic,所有的延迟函数都会被执行,并且程序会崩溃,其日志信息包括 panic 值(通常是错误信息)和堆栈跟踪。

举个例子,当一个数字被除以0时,Golang会出现 panic。


package main

import "fmt"

func main(){
	divide(5)
}

func divide(x int){
	fmt.Printf("divide(%d)\n",x+0/x)
	divide(x-1)
}

divide(5)
divide(4)
divide(3)
divide(2)
divide(1)
panic: runtime error: integer divide by zero

goroutine 1 [running]:
main.divide(0x0)
        /Users/zidea2020/Desktop/mysite/go_tut/main.go:10 +0xdb
main.divide(0x1)
        /Users/zidea2020/Desktop/mysite/go_tut/main.go:11 +0xcc
main.divide(0x2)
        /Users/zidea2020/Desktop/mysite/go_tut/main.go:11 +0xcc
main.divide(0x3)
        /Users/zidea2020/Desktop/mysite/go_tut/main.go:11 +0xcc
main.divide(0x4)
        /Users/zidea2020/Desktop/mysite/go_tut/main.go:11 +0xcc
main.divide(0x5)
        /Users/zidea2020/Desktop/mysite/go_tut/main.go:11 +0xcc
main.main()
        /Users/zidea2020/Desktop/mysite/go_tut/main.go:6 +0x2a
exit status 2

Recover

Go语言提供了recover内置函数,前面提到,一旦panic,逻辑就会走到defer那,那我们就在defer那等着,调用recover函数将会捕获到当前的panic,被捕获到的panic就不会向上传递了。然后,恢复将结束当前的 Panic 状态,并返回 Panic 的错误值。


package main

import "fmt"

func main(){
	accessSlice([]int{1,2,5,6,7,8}, 0)
}

func accessSlice(slice []int, index int) {
	defer func() {
		if p := recover(); p != nil {
			fmt.Printf("internal error: %v", p)
		}
	}()

	fmt.Printf("item %d, value %d \n", index, slice[index])
	defer fmt.Printf("defer %d \n", index)
	accessSlice(slice, index+1)
}

包装错误

Golang 也允许对错误进行包裹,通过错误嵌套,在原有错误信息上添加一个额外信息帮助调用者对问题判断以及后续应该如何处理信息。以通过使用 %w 标志和 fmt.Errorf 函数来对原有的错误进行保存提供一些特定的信息,如下例所示。


package main

import (
	"errors"
	"fmt"
	"os"
)

func main() {
	err := openFile("non-existing")

	if err != nil {
		fmt.Printf("error running program: %s \n", err.Error())
	}
}

func openFile(filename string) error {
	if _, err := os.Open(filename); err != nil {
		return fmt.Errorf("error opening %s: %w", filename, err)
	}

	return nil
}

上面已经通过代码演示如何包装一个错误,程序会打印输出使用 fmt.Errorf 添加文件名的包装过的错误,也打印了传递给 %w 标志的原有错误信息。这里再补充一个 Golang 还提供的功能,通过使用 error.Unwrap 来还原错误信息,从而获得原有的错误信息。


package main

import (
	"errors"
	"fmt"
	"os"
)

func main() {
	err := openFile("non-existing")

	if err != nil {
		fmt.Printf("error running program: %s \n", err.Error())

		// Unwrap error
		unwrappedErr := errors.Unwrap(err)
		fmt.Printf("unwrapped error: %v \n", unwrappedErr)
	}
}

func openFile(filename string) error {
	if _, err := os.Open(filename); err != nil {
		return fmt.Errorf("error opening %s: %w", filename, err)
	}

	return nil
}

错误的类型转换

有时候需要在不同的错误类型之间进行转换,有情况需要通过类型转换来为错误添加信息,或者换一种表达方式,。 errors.As 函数提供了一个简单而安全的方法,通过寻找错误链中匹配错误类型进行转化输出。如果没有找到匹配的,该函数返回 false 。


package main

import (
	"errors"
	"fmt"
	"io/fs"
	"os"
)

func main(){
	// Casting error
	if _, err := os.Open("non-existing"); err != nil {
		var pathError *os.PathError
		if errors.As(err, &pathError) {
			fmt.Println("Failed at path:", pathError.Path)
		} else {
			fmt.Println(err)
		}
	}
}

在这里,试图将通用错误类型转换为 os.PathError ,这样就可以访问该特定的错误信息,这些信息保存在结构体中的 Path 属性上。

错误类型检查

Golang 提供了 errors.Is 函数来用于检查错误类型是否为指定的错误类型,该函数返回一个布尔值值来表示是否为指定错误类型。


package main

import (
	"errors"
	"fmt"
	"io/fs"
	"os"
)

func main(){
	// Check if error is a specific type
	if _, err := os.Open("non-existing"); err != nil {
		if errors.Is(err, fs.ErrNotExist) {
			fmt.Println("file does not exist")
		} else {
			fmt.Println(err)
		}
	}
}

到此这篇关于golang 语言中错误处理机制的文章就介绍到这了,更多相关golang 错误处理内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

golang 语言中错误处理机制

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

golang函数中错误处理机制详解

golang 函数中错误处理机制利用 error 类型和 error 标准接口来处理错误。错误类型可自定义,通过 error() 方法返回错误描述。错误处理机制包括显式错误(通过返回值传递错误)和隐式错误(通过 panic 终止函数)。显式
golang函数中错误处理机制详解
2024-05-03

golang函数的错误处理机制

go 语言函数的错误处理机制是通过返回一个类型为 error 的值来指示执行状态。错误处理方法包括:1. 裸返回错误值;2. 使用 fmt.errorf 包装错误;3. 使用 errors.is 和 errors.as 检查错误类型;4.
golang函数的错误处理机制
2024-04-29

学习 Go 语言中的错误处理与恢复机制

从现在开始,努力学习吧!本文《学习 Go 语言中的错误处理与恢复机制》主要讲解了等等相关知识点,我会在编程网中持续更新相关的系列文章,欢迎大家关注并积极留言建议。下面就先一起来看一下本篇正文内容吧,希望能帮到你!Go 语言是一种静态类型、编
学习 Go 语言中的错误处理与恢复机制
2024-04-04

深度探索Golang中的错误处理机制

深入理解Golang中的错误处理机制Golang作为一门高效、并发性强的编程语言,其错误处理机制在编写程序时非常重要。在Golang中,错误被视为普通的返回值,而不是像其他语言一样通过异常来处理。本文将深入探讨Golang中的错误处理机制
深度探索Golang中的错误处理机制
2024-02-24

不同语言中错误处理与Go语言错误处理的差异

不同编程语言的错误处理方式不同,如 javascript 使用 try...catch 块,java 使用异常类。go 语言使用错误值,一种表示错误详细信息的接口类型。函数可以通过返回错误值来指示操作失败。可以使用 if 语句或 error
不同语言中错误处理与Go语言错误处理的差异
2024-04-12

golang函数式编程中的错误处理机制

go 语言函数式编程中,错误处理至关重要,可通过错误对象、error 类型和错误处理操作符进行管理。具体操作方式包括:if 语句:检测错误并根据情况返回。errors.is 和 errors.as:检查错误类型,以便处理或存储特定错误类型。
golang函数式编程中的错误处理机制
2024-05-04

golang函数中goroutine的错误处理机制是什么?

默认情况下,go 中 goroutine 中的错误会被忽略,需要明确处理。处理方法有:1. 使用 panic 和 recover 函数捕获异常;2. 使用 errors 通道传递错误,以便在主函数中收集和处理错误。Go 语言函数中 Goro
golang函数中goroutine的错误处理机制是什么?
2024-05-05

深入理解golang函数的错误处理机制

在 go 中,函数通过 error 变量表示错误,这是一个实现了 error() 方法的接口。如果函数成功执行,则 error 变量应为 nil。而要将错误从函数中传播出来,需要在函数签名中指定返回值类型为 error。通过检查返回的 er
深入理解golang函数的错误处理机制
2024-04-24

如何为Golang函数提供错误处理机制?

golang 提供了以下错误处理机制:使用内置的 error 类型: 最简单的方法,任何实现了 error() 方法的类型都可以作为错误。自定义错误类型: 定义一个实现了 error() 方法的结构体,以提供更具体的信息。使用第三方包: 如
如何为Golang函数提供错误处理机制?
2024-04-12

使用golang的错误包装和展开机制进行错误处理

go 中的错误处理包括包装错误和展开错误。包装错误允许用一个错误类型包装另一个,提供更丰富上下文的错误。展开错误遍历嵌套错误链,找到最底层错误,便于调试。通过结合使用这两种技术,可以有效处理错误条件,提供更丰富的错误上下文和更好的调试能力。
使用golang的错误包装和展开机制进行错误处理
2024-04-25

Pygame在Ubuntu中的错误处理机制

Pygame是一个用于编写视频游戏的Python库,它提供了图像、声音、事件处理等功能。在Ubuntu中,Pygame的错误处理机制通常涉及到以下几个方面:异常捕获:在Python中,你可以使用try-except语句来捕获和处理异常。当你
Pygame在Ubuntu中的错误处理机制
2024-10-13

Linux中Ruby应用错误处理机制

在 Linux 系统中,Ruby 语言的错误处理机制主要依赖于异常处理以下是 Ruby 中常见的错误类型:StandardError:这是 Ruby 中所有标准错误的基类。大多数错误都继承自这个类。ArgumentError:当方法接收
Linux中Ruby应用错误处理机制
2024-09-16

ASP中的错误处理机制是什么

在ASP中,错误处理机制主要通过错误处理页面、On Error语句和错误对象(Error Object)来实现。错误处理页面:可以使用自定义的错误处理页面来处理ASP页面中的错误。通过设置web.config文件中的customErrors
ASP中的错误处理机制是什么
2024-04-03

Go语言的错误处理方式

这篇文章主要介绍“Go语言的错误处理方式”,在日常操作中,相信很多人在Go语言的错误处理方式问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Go语言的错误处理方式”的疑惑有所帮助!接下来,请跟着小编一起来学习吧
2023-06-15

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录