2Go语言错误处理

Posted 行走的皮卡丘

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2Go语言错误处理相关的知识,希望对你有一定的参考价值。

2、Go语言错误处理

1、defer 延迟执行

1.1 defer延迟执行修饰符

Go语言提供的defer机制,可以让开发者在创建资源(比如:数据库连接、文件句柄、锁等) 后,能够及时释放资源:

func main() 
	//当执行到defer语句时,暂不执行,会将defer后的语句压入到独立的栈中,当函数执行完毕后,再从该栈按照先入后出的方式出栈执行
	defer fmt.Println("defer1...")
	defer fmt.Println("defer2...")
	fmt.Println("main...")

上述代码执行结果

main...
defer2...
defer1...

defer将语句放入到栈时,也会将相关的值拷贝同时入栈:

func main() 
	num := 0
	defer fmt.Println("defer中:num=", num)
	num = 3
	fmt.Println("main中:num=",num)

输出结果:

main中:num= 3
defer中:num= 0

1.2 defer最佳实践

案例一:defer处理资源

没有使用defer时打开文件处理代码:

f,err := os.Open(file)
if err != nil 
	return 0


info,err := f.Stat()
if err != nil 
	f.Close()
	return 0


f.Close()
return 0;

使用defer优化:

f,err := os.Open(file)
if err != nil 
	return 0


defer f.Close()

info,err := f.Stat()

if err != nil 
	// f.Close()			//这句已经不需要了
	return 0


//后续一系列文件操作后执行关闭
// f.Close()			//这句已经不需要了
return 0;

案例二:并发使用map的函数。

无defer代码:

var (
	mutex sync.Mutex
	testMap = make(map[string]int)
)
func getMapValue(key string) int 
	mutex.Lock()						//对共享资源加锁
	value := testMap[key]
	mutex.Unlock()
	return value

上述案例是很常见的对并发map执行加锁执行的安全操作,使用defer可以对上述语义进行简化:

var (
	mutex sync.Mutex
	testMap = make(map[string]int)
)
func getMapValue(key string) int 
	mutex.Lock()						//对共享资源加锁
	defer mutex.Unlock()
	return testMap[key]

1.3 defer无法处理全局资源

使用defer语句, 可以方便地组合函数/闭包和资源对象,即使panic时,defer也能保证资源的正确释放。但是上述案例都是在局部使用和释放资源,如果资源的生命周期很长, 而且可能被多个模块共享和随意传递的话,defer语句就不好处理了。

Go的runtime包的func SetFinalize(x, f interface)函数可以提供类似C++析构函数的机制。

示例:包装一个文件对象,在没有人使用的时候能够自动关闭。

type MyFile struct 
	f *os.File


func NewFile(name string) (&MyFile, error)
	file, err := os.Open(name)
	if err != nil 
		return nil, err
	
	runtime.SetFinalizer(file, file.f.Close)
	return &MyFilef: file, nil

在使用runtime.SetFinalizer时, 需要注意的地方是尽量要用指针访问内部资源,这样的话, 即使*MyFile对象忘记释放, 或者是被别的对象无意中覆盖, 也可以保证内部的文件资源可以正确释放。

2、Error 错误

2.1 Go自带的错误接口

error是go语言声明的接口类型:

type error interface 
	Error() string

所有符合Error()string格式的方法,都能实现错误接口,Error()方法返回错误的具体描述。

2.2 自定义错误

返回错误前,需要定义会产生哪些可能的错误,在Go中,使用errors包进行错误的定义,格式如下:

var err = errors.New("发生了错误")

提示:错误字符串相对固定,一般在包作用于声明,应尽量减少在使用时直接使用errors.New返回。

errors.New使用示例:

func Sqrt(f float64) (float64, error) 
	if f < 0 
		return 0, errors.New("math: square root of negative number")
	
	// implementation

err常见使用方式:

f, err := os.Open("filename.ext")
if err != nil 
	fmt.Println(err)

实现错误接口案例:

package main

import (
	"fmt"
)

//声明一种解析错误
type ParseError struct 
	Filename string
	Line int


//实现error接口,返回错误描述
func (e *ParseError) Error() string 
	return fmt.Sprintf("%s:%d", e.Filename, e.Line)


//创建一些解析错误
func newParseError(filename string, line int) error 
	return &ParseErrorfilename, line


func main() 

	var e error

	e = newParseError("main.go", 1)

	fmt.Println(e.Error())

	switch detail := e.(type) 
	case *ParseError:
		fmt.Printf("Filename: %s Line:%d \\n", detail.Filename, detail.Line)
	default: 
		fmt.Println("other error")
	


3、panic 宕机

Go语言可以在程序中手动触发宕机,让程序崩溃,这样开发者可以及时发现错误:

package main

func main() 
	defer fmt.Println("before")		// panic()前面已经运行过的defer语句依然会在宕机时发生作用
	panic("crash")					// panic()参数可以是任意类型
	fmt.Println("after")			// panic()后面的代码将不会执行

运行结果是:

before
panic: crash

goroutine 1 [running]:
main.main()

注意:手动触发宕机并不是一种偷懒的方式,反而能迅速报错,终止程序继续运行,防止更大的错误产生,但是如果任何错误都使用宕机处理,也不是一个良好的设计。

4、recover 宕机恢复

Go提供的recover机制:由运行时抛出,或者开发者主动触发的panic,可以使用defer和recover实现错误捕捉和处理,让代码在发生崩溃后允许继续执行。

在其他语言里,宕机往往以异常的形式存在,底层抛出异常,上层逻辑通过try/catch机制捕获异常,没有被捕获的严重异常会导致宕机,捕获的异常可以被忽略,让代码继续执行。Go没有异常系统,使用panic触发宕机类似于其他语言的抛出异常,recover的宕机恢复机制就对应try/catch机制。

panic和defer的组合:

  • 有panic没有recover,程序宕机
  • 有panic也有recover,程序不会宕机,执行完对应的defer后,从宕机点退出当前函数后继续执行

示例:

package main

import "fmt"

func test(num1 int, num2 int)
	defer func()
		err := recover()				// recover内置函数,可以捕获异常
		if err != nil 
			fmt.Println("err=", err)
		
	()
	fmt.Println(num1/num2)


func main() 
	test(2,0)
	fmt.Println("after...")			// 该句会输出

以上是关于2Go语言错误处理的主要内容,如果未能解决你的问题,请参考以下文章

2Go语言错误处理

2Go语言基础之数据类型

2Go语言基础之数据类型

GO语言学习(十九)Go 错误处理

go语言学习---错误处理

GO语言基础之error