Go 入门很简单:panic 和 recover

举报
宇宙之一粟 发表于 2022/03/31 00:18:58 2022/03/31
【摘要】 前言panic 和 recover 可以被认为类似于其他语言(如 Java)中的 try-catch-finally 习惯用法,只是它们在 Go 中很少使用。Go 中一个重要的点是我们应该尽可能避免使用 panic 和 revover ,可以多多使用 error 。只有在程序无法继续执行的情况下,才应该使用 panic 和 revover 机制。 使用 error 错误处理 Go 程序中的...

前言

panicrecover 可以被认为类似于其他语言(如 Java)中的 try-catch-finally 习惯用法,只是它们在 Go 中很少使用。

Go 中一个重要的点是我们应该尽可能避免使用 panicrevover ,可以多多使用 error 。只有在程序无法继续执行的情况下,才应该使用 panicrevover 机制。

使用 error 错误

处理 Go 程序中的异常情况的惯用方法是使用 errorerror 足以处理程序中出现的大多数异常情况。

但有些情况下,程序在出现异常情况后无法继续执行。在这种情况下,我们使用 panic 来提前终止程序。

当一个函数遇到 panic 时,它的执行被停止,任何延迟的函数被执行,然后控制权返回给它的调用者。这个过程一直持续到当前 goroutine 的所有函数都返回为止,这时程序会打印出 panic 信息,然后是堆栈跟踪,然后终止。

什么时候使用 panic

  1. 程序不能轻易地继续执行的不可恢复的错误。
    一个示例是无法绑定到所需端口的 Web 服务器。在这种情况下,panic 是合理的,因为如果端口绑定失败,则后续操作无法进行下去。
  2. 程序员错误。
    假设我们有一个接受指针作为参数的方法,并且有人使用 nil 参数调用此方法。在这种情况下,我们可能可以使用 panic ,因为调用带有 nil 参数的方法是程序员错误,该方法期望一个有效的指针。

panic 例子

首先我们看一下 panic 的内置方法:

func panic(interface{})

当程序终止时,传递给 panic 函数的参数会被打印。
我们来看一个例子:

package main

import (
	"fmt"
)

func fullName(firstName *string, lastName *string) {
	if firstName == nil {
		panic("runtime error: first name cannot be nil")
	}
	if lastName == nil {
		panic("runtime error: last name cannot be nil")
	}
	fmt.Printf("%s %s\n", *firstName, *lastName)
	fmt.Println("returned normally from fullName")
}

func main() {
	firstName := "Ray"
	fullName(&firstName, nil)
	fmt.Println("returned normally from main")
}

运行会立马报错终止:

panic: runtime error: last name cannot be nil

goroutine 1 [running]:
main.fullName(0x405058?, 0xc000088f70?)
	/home/wade/go/src/panicAndrevcover/panicRecover.go:12 +0x114
main.main()
	/home/wade/go/src/panicAndrevcover/panicRecover.go:20 +0x35
exit status 2

让我们分析这个输出以了解 panic 是如何工作的,以及当程序 panic 时堆栈跟踪是如何打印的。

在第代码的 19 行 我们将 Ray 分配给 firstName。

我们在第 1 行调用 fullName 函数,lastName 为 nil。 第 20 行调用 fullName 函数时 lastname 为空 nil

因此第 11 行程序就会出现 panic,程序终止运行,这个参数传递给 panic 函数打印到终端。

然后时堆栈追踪,因为程序会在第 20 行的 panic 函数调用之后终止,代码中的 13, 14, 15 行不会被执行。

运行结果解释:

所以,这段程序首先会打印传递给 panic 函数的信息:

panic: runtime error: last name cannot be nil  

然后打印堆栈追踪,程序在第 12 行的 fullname 函数调用 panic,所以输出:

goroutine 1 [running]:
main.fullName(0x405058?, 0xc000088f70?)
	/home/wade/go/src/panicAndrevcover/panicRecover.go:12 +0x114

然后栈中的下一个元素会被打印,第 20 行调用的 fullname,所以再输出:

	/home/wade/go/src/panicAndrevcover/panicRecover.go:20 +0x35
exit status 2

现在我们已经到达了导致 panic 的顶层函数,之后没有更高层了,因此没有更多可以打印的内容。

另一个例子

panic 也可能是由运行时发生的错误引起的,例如尝试访问切片中不存在的索引。

package main

import (  
    "fmt"
)

func slicePanic() {  
    n := []int{5, 7, 4}
    fmt.Println(n[4])
    fmt.Println("normally returned from a")
}
func main() {  
    slicePanic()
    fmt.Println("normally returned from main")
}

在上面的程序中,第 9 行正在尝试访问 n[4] ,它是切片中的无效索引。该程序将出现以下输出 panic:

panic: runtime error: index out of range [4] with length 3

goroutine 1 [running]:
main.slicePanic()
	/home/wade/go/src/panicAndrevcover/panicRecover.go:9 +0x1d
main.main()
	/home/wade/go/src/panicAndrevcover/panicRecover.go:13 +0x19
exit status 2

文章来源:

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。