ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Go语言中常见100问题-#48 panic

2022-06-21 10:05:07  阅读:154  来源: 互联网

标签:-# 48 fmt Println func Go main panic go


panic会终止代码执行逻辑

panic语句会终止代码执行,即fmt.Println("b")不会被执行.

func main() {
 fmt.Println("a")
 panic("foo")
 fmt.Println("b")
 // panic之后的内容不会输出,类似于linux中的exit函数功能,程序直接退出
}

上面程序输出如下:

a
panic: foo

goroutine 1 [running]:
main.main()
        main.go:7 +0x95
exit status 2

panic异常执行流程

panic语句被执行后,异常执行流程有两种情况。情况1:panic没有被recover,执行逻辑将沿调用栈返回,直到goroutine退出。情况2:panic被recover捕获结束。

  • panic没有被捕获

下面的panic语句执行后,因为没有被捕获,所以沿着调用栈 main->fa->fb->fc 一路返回到到main中,然后程序直接退出了,main中的fd不会输出。因为在Go中,「如果一个goroutine panic了,而且这个goroutine里面没有捕获recover,那么整个进程就会挂掉」.

func main() {
 go fa()
 time.Sleep(time.Second)
 fd()
}

func fa() {
 fmt.Println("call fa")
 fb()
}

func fb() {
 fmt.Println("call fb")
 fc()
}

func fc() {
 fmt.Println("call fc")
 panic("fc")
 fmt.Println("call fc end")
}

func fd() {
 fmt.Println("call fd")
}

上面的程序执行输出如下:

call fa
call fb
call fc
panic: fc

goroutine 6 [running]:
main.fc()
        main.go:26 +0x95
main.fb()
        main.go:21 +0x7a
main.fa()
        main.go:16 +0x7a
created by main.main
       main.go:9 +0x39
exit status 2
  • panic被捕获

下面程序中的panic异常被recover捕获,异常从ff返回后在f中被捕获处理了,main中的main end能够正常输出,并且程序不会挂掉。

func main() {
 f()

 fmt.Println("main end")
}

func f() {
 defer func() {
  if r := recover(); r != nil {
   fmt.Println("recover", r)
  }
 }()

 ff()

 fmt.Println("f end")
}

func ff() {
 fmt.Println("a")
 panic("foo")
 fmt.Println("b")
}

上面的程序输出结果为:

a
recover foo
main end

需要注意的是,捕获代码recover逻辑需要放在defer语句中,否则函数将返回nil,看不到任何效果,因为defer语句在panic后也会被执行到。例如下面的程序,recover没有放在defer函数中,panic没有被捕获到。

func main() {
 f()

 fmt.Println("main end")
}

func f() {
 if r := recover(); r != nil {
  fmt.Println("recover", r)
 }

 ff()

 fmt.Println("f end")
}

func ff() {
 fmt.Println("a")
 panic("foo")
 fmt.Println("b")
}

上面的程序输出结果为:

a
panic: foo

goroutine 1 [running]:
main.ff()
        main.go:23 +0x95
main.f()
       main.go:16 +0x46
main.main()
       main.go:6 +0x22
exit status 2

panic使用场景

在实际的工程项目中,对于错误处理通常都是采用error处理,使用panic是比较少的。看过Go源码的同学会注意到,源码中使用panic和throw是比较多的。那在什么场景下使用panic合适呢?

书中提到了两种适合采用panic的场景。场景1:使用在真正有异常的情况,例如程序员的错误。场景2:程序需要使用其他依赖,但是初始化失败。

对于场景1,书中列举了两个例子。例子1说的是net/http包中的WriteHeader方法,它调用checkWriteHeaderCode函数时,该函数中用到panic函数。

func checkWriteHeaderCode(code int) {
        if code < 100 || code > 999 {
                panic(fmt.Sprintf("invalid WriteHeader code %v", code))
        }
}

这里对http状态码的校验时候,如果不在[100,999]范围内直接panic,并且不捕获错误,出现这种情况,程序会直接挂掉。因为http协议对状态码有规范,如果传入的code值不在合法范围,说明程序员在传入的参数出现问题,这种人为存在的问题,直接panic让程序退出,显示暴露问题的做法比较合理。

例2来自database/sql中的代码,在注册驱动Register函数中,如果driver为nil或者重复注册,这种也是人使用不当导致的问题,也直接panic。

func Register(name string, driver driver.Driver) {
        driversMu.Lock()
        defer driversMu.Unlock()
        if driver == nil {
                panic("sql: Register driver is nil")
        }
        if _, dup := drivers[name]; dup {
                panic("sql: Register called twice for driver " + name)
        }
        drivers[name] = driver
}

go-sql-driver/mysql(Go中使用最多的MySQL驱动库)中,Register是通过init函数调用的,限制了error处理。综合这些因素,作者在设计的时候直接让程序panic处理。

// driver.go line 83
func init() {
 sql.Register("mysql", &MySQLDriver{})
}

对于场景2,如果我们的程序依赖需要其他依赖,但是依赖初始化失败,我们的程序是没法工作的。例如,我们提供的一个创建账户的服务,服务某个处理过程中需要对用户提供的邮箱地址进行验证,我们决定采用正则表达式对email address进行校验。

在Go中,regexp包提供了两个创建正则的函数,它们是Compile和MustCompile。前者返回的是regexp.Regexp和一个error. 然而后者只返回一个regexp.Regexp,但是出现错误,会直接panic,这是一种强依赖,的确,如果compile失败,将不能够验证任何输入的邮箱地址。因此,相比返回错误,采用MustCompile和panic要更合适。

panic使用的场景是很少的,除了上面提到的程序人员导致的错误和依赖初始化失败情况外,其他采用error处理。

 

 

 

标签:-#,48,fmt,Println,func,Go,main,panic,go
来源: https://www.cnblogs.com/tracydzf/p/16395829.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有