前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【初识Go】| Day10 异常处理

【初识Go】| Day10 异常处理

原创
作者头像
yussuy
修改2020-12-24 10:07:21
2350
修改2020-12-24 10:07:21
举报

error

针对这样的情况,Go语言中引入 error 接口类型作为错误处理的标准模式,如果函数要返回错误,则返回值类型列表中肯定包含 error。error 处理过程类似于C语言中的错误码,可逐层返回,直到被处理。

Go语言内置了一个简单的错误接口作为一种错误处理机制,接口定义如下:

代码语言:txt
复制
type error interface {
	Error() string
}

它包含一个 Error() 方法,返回值为string

error 基本用法

Go的error构造有两种方式,分别是

第一种:errors.New()

代码语言:txt
复制
err := errors.New("This is an error")
if err != nil {
  fmt.Print(err)
}

第二种(更常使用):fmt.Errorf()

代码语言:txt
复制
err := fmt.Errorf("This is an error")
if err != nil {
  fmt.Print(err)
}

自定义错误类型

除了上面的 errors.New 用法之外,我们还可以使用 error 接口自定义一个 Error() 方法,来返回自定义的错误信息。下面以自然数函数作为例子:

代码语言:txt
复制
type NotNature float64

func (err NotNature) Error() string {
 return fmt.Sprintf("自然数为大于或等于0的数: %v", float64(err))
}

func Nature(x float64) (float64,error) {
  if x<0 {
   return 0,NotNature(x)
  } else {
  return x,nil
  }
}

func main() {
  fmt.Println(Nature(1))
  fmt.Println(Nature(-1))
}

需要注意一下几点:

1.如果函数需要处理异常,通常将error作为多值返回的最后一个值,返回的error值为nil则表示无异常,非nil则是有异常。

2.一般先用if语句处理error!=nil,正常逻辑放if后面。

Go语言的error代表的并不是真“异常”,只是通过返回error来表示错误信息,换句话说,不是运行时错误范围预定义的错误,某种不符合期望的行为并不会导致程序无法运行(自然数函数例子),都应使用error进行异常处理。当程序出现重大错误,如数组越界,才会将其当成真正的异常,并用panic来处理。

panic

Go不使用try...catch方法来处理异常,而是使用panicrecover

Go的类型系统会在编译时捕获很多错误,但有些错误只能在运行时检查,如数组访问越界、空指针引用等。这些运行时错误会引起painc异常。

一般而言,当panic异常发生时,程序会中断运行,并立即执行在该goroutine(在Day14并发编程中将会学习到)中被延迟的函数(defer 机制)。随后,程序崩溃并输出日志信息。日志信息包括panic value和函数调用的堆栈跟踪信息。panic value通常是某种错误信息。对于每个goroutine,日志信息中都会有与之相对的,发生panic时的函数调用堆栈跟踪信息。通常,我们不需要再次运行程序去定位问题,日志信息已经提供了足够的诊断依据。因此,在我们填写问题报告时,一般会将panic异常和日志信息一并记录。

不是所有的panic异常都来自运行时,直接调用内置的panic函数也会引发panic异常;panic函数接受任何值作为参数。当某些不应该发生的场景发生时,我们就应该调用panic。比如,当程序到达了某条逻辑上不可能到达的路径。举一个简单的例子:

代码语言:txt
复制
func main() {
  fmt.Println("Hello,Go!")
  panic(errors.New(" i am a error"))
  fmt.Println("hello,again!")
}

输出:

代码语言:txt
复制
Hello,Go!
panic:  i am a error

goroutine 1 [running]:
main.main()
	~/error.go:12 +0xb5
exit status 2

可以看到,panic后面的程序不会被执行了。但是我们捕捉异常并不是为了停止程序(一般情况),而是为了让程序能正常运行下去,这时候就到recover出场了。

代码语言:txt
复制
package main

import "fmt"

func main(){
  defer func(){
    fmt.Println("我是defer里面第一个打印函数")
    if err:=recover();err!=nil{
        fmt.Println(err)
    }
    fmt.Println("我是defer里面第二个打印函数")
  }()
  f()
}

func f(){
  fmt.Println("1")
  panic("我是panic")
  fmt.Println("2")
}

输出:

代码语言:txt
复制
1
我是defer里面第一个打印函数
我是panic
我是defer里面第二个打印函数

可以看到,f函数一开始正常打印,当遇到panic,就跳到defer函数,执行defer函数里的内容

需要注意的是,defer函数里打印的err其实就是panic里面的内容。

下面详细介绍一下panic和recover的原理。首先来看一下panic和recover的官方定义

代码语言:txt
复制
func panic(v interface{})

内置函数panic会停止当前goroutine的正常执行。当函数F调用panic时,F的正常执行立即停止。任何被F延迟执行的函数都将以正常的方式运行,然后F返回其调用者。对调用方G来说,对F的调用就像调用panic一样,终止G的执行并运行任何延迟的函数。直到执行goroutine中的所有函数都按逆序停止。此时,程序将以非0退出代码终止。此终止序列称为panicking,可由内置函数recover控制。

代码语言:txt
复制
func recover() interface{}

recover内置函数允许程序管理panicking的goroutine的行为。在defer函数(但不是它调用的任何函数)内执行恢复调用,通过恢复正常执行来停止panicking序列,并检索传递给panic调用的错误值。如果在defer函数之外调用recover,则不会停止panicking的序列。在这种情况下,或者当goroutine不panicking时,或者提供给panic的参数是nil,recover返回nil。因此,recover的返回值报告goroutine是否panicking

ps:defer和recover必须在panic之前定义,否则无效。

源码分析

整个errors包仅只有4行:

代码语言:txt
复制
package errors

func New(text string) error { return &errorString{text} }

type errorString struct { text string }

func (e *errorString) Error() string { return e.text }

承载errorString的类型是一个结构体而非一个字符串,这是为了保护它表示的错误避免粗心(或有意)的更新。并且因为是指针类型*errorString满足error接口而非errorString类型,所以每个New函数的调用都分配了一个独特的和其他错误不相同的实例。我们也不想要重要的error例如io.EOF和一个刚好有相同错误消息的error比较后相等。

代码语言:txt
复制
fmt.Println(errors.New("EOF") == errors.New("EOF")) // "false"

总体来说:

1.New函数返回格式为给定文本的错误

2.即使文本是相同的,每次对New的调用都会返回一个不同的错误值。

参考资料

http://shouce.jb51.net/gopl-zh/ch7/ch7-08.html

http://shouce.jb51.net/gopl-zh/ch5/ch5-09.html

http://c.biancheng.net/view/4284.html

https://github.com/datawhalechina/go-talent/blob/master/9.%E5%BC%82%E5%B8%B8%E5%A4%84%E7%90%86.md

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • error
    • error 基本用法
      • 自定义错误类型
      • panic
      • 源码分析
      • 参考资料
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档