go panic recover 异常处理
Go语言追求简洁优雅,所以,Go语言不支持传统的 try…catch…finally 这种异常,因为Go语言的设计者们认为,将异常与控制结构混在一起会很容易使得代码变得混乱。因为开发者很容易滥用异常,甚至一个小小的错误都抛出一个异常。在Go语言中,使用多值返回来返回错误。不要用异常代替错误,更不要用来控制流程。在极个别的情况下,也就是说,遇到真正的异常的情况下(比如除数为0了)。才使用Go中引入的Exception处理:defer, panic, recover。
这几个异常的使用场景可以这么简单描述:Go中可以抛出一个panic的异常,然后在defer中通过recover捕获这个异常,然后正常处理
主要参考:https://blog.golang.org/defer-panic-and-recover
package main
import "fmt"
func main() {
f()
fmt.Println("Returned normally from f.")
}
func f() {
defer func() {
if r := recover(); r != nil {
fmt.Println("Recovered in f", r)
}
}()
fmt.Println("Calling g.")
g(0)
fmt.Println("Returned normally from g.")
}
func g(i int) {
if i > 3 {
fmt.Println("Panicking!")
panic(fmt.Sprintf("%v", i))
}
defer fmt.Println("Defer in g", i)
fmt.Println("Printing in g", i)
g(i + 1)
}
The Go Blog
Defer, Panic, and Recover
4 August 2010
Go has the usual mechanisms for control flow: if, for, switch, goto. It also has the go statement to run code in a separate goroutine. Here I'd like to discuss some of the less common ones: defer, panic, and recover.
A defer statement pushes a function call onto a list. The list of saved calls is executed after the surrounding function returns. Defer is commonly used to simplify functions that perform various clean-up actions.
For example, let's look at a function that opens two files and copies the contents of one file to the other:
func CopyFile(dstName, srcName string) (written int64, err error) {
src, err := os.Open(srcName)
if err != nil {
return
}
dst, err := os.Create(dstName)
if err != nil {
return
}
written, err = io.Copy(dst, src)
dst.Close()
src.Close()
return
}
This works, but there is a bug. If the call to os.Create fails, the function will return without closing the source file. This can be easily remedied by putting a call to src.Close before the second return statement, but if the function were more complex the problem might not be so easily noticed and resolved. By introducing defer statements we can ensure that the files are always closed:
func CopyFile(dstName, srcName string) (written int64, err error) {
src, err := os.Open(srcName)
if err != nil {
return
}
defer src.Close()
dst, err := os.Create(dstName)
if err != nil {
return
}
defer dst.Close()
return io.Copy(dst, src)
}
Defer statements allow us to think about closing each file right after opening it, guaranteeing that, regardless of the number of return statements in the function, the files will be closed.
The behavior of defer statements is straightforward and predictable. There are three simple rules:
1. A deferred function's arguments are evaluated when the defer statement is evaluated.
In this example, the expression "i" is evaluated when the Println call is deferred. The deferred call will print "0" after the function returns.
func a() {
i := 0
defer fmt.Println(i)
i++
return
}
2. Deferred function calls are executed in Last In First Out order after the surrounding function returns.
This function prints "3210":
func b() {
for i := 0; i < 4; i++ {
defer fmt.Print(i)
}
}
3. Deferred functions may read and assign to the returning function's named return values.
In this example, a deferred function increments the return value i after the surrounding function returns. Thus, this function returns 2:
func c() (i int) {
defer func() { i++ }()
return 1
}
This is convenient for modifying the error return value of a function; we will see an example of this shortly.
Panic is a built-in function that stops the ordinary flow of control and begins panicking. When the function F calls panic, execution of F stops, any deferred functions in F are executed normally, and then F returns to its caller. To the caller, F then behaves like a call to panic. The process continues up the stack until all functions in the current goroutine have returned, at which point the program crashes. Panics can be initiated by invoking panic directly. They can also be caused by runtime errors, such as out-of-bounds array accesses.
Recover is a built-in function that regains control of a panicking goroutine. Recover is only useful inside deferred functions. During normal execution, a call to recover will return nil and have no other effect. If the current goroutine is panicking, a call to recover will capture the value given to panic and resume normal execution.
Here's an example program that demonstrates the mechanics of panic and defer:
package main
import "fmt"
func main() {
f()
fmt.Println("Returned normally from f.")
}
func f() {
defer func() {
if r := recover(); r != nil {
fmt.Println("Recovered in f", r)
}
}()
fmt.Println("Calling g.")
g(0)
fmt.Println("Returned normally from g.")
}
func g(i int) {
if i > 3 {
fmt.Println("Panicking!")
panic(fmt.Sprintf("%v", i))
}
defer fmt.Println("Defer in g", i)
fmt.Println("Printing in g", i)
g(i + 1)
}
The function g takes the int i, and panics if i is greater than 3, or else it calls itself with the argument i+1. The function f defers a function that calls recover and prints the recovered value (if it is non-nil). Try to picture what the output of this program might be before reading on.
The program will output:
Calling g.
Printing in g 0
Printing in g 1
Printing in g 2
Printing in g 3
Panicking!
Defer in g 3
Defer in g 2
Defer in g 1
Defer in g 0
Recovered in f 4
Returned normally from f.
If we remove the deferred function from f the panic is not recovered and reaches the top of the goroutine's call stack, terminating the program. This modified program will output:
Calling g.
Printing in g 0
Printing in g 1
Printing in g 2
Printing in g 3
Panicking!
Defer in g 3
Defer in g 2
Defer in g 1
Defer in g 0
panic: 4 panic PC=0x2a9cd8
[stack trace omitted]
For a real-world example of panic and recover, see the json package from the Go standard library. It decodes JSON-encoded data with a set of recursive functions. When malformed JSON is encountered, the parser calls panic to unwind the stack to the top-level function call, which recovers from the panic and returns an appropriate error value (see the 'error' and 'unmarshal' methods of the decodeState type in decode.go).
The convention in the Go libraries is that even when a package uses panic internally, its external API still presents explicit error return values.
Other uses of defer (beyond the file.Close example given earlier) include releasing a mutex:
mu.Lock()
defer mu.Unlock()
printing a footer:
printHeader()
defer printFooter()
and more.
In summary, the defer statement (with or without panic and recover) provides an unusual and powerful mechanism for control flow. It can be used to model a number of features implemented by special-purpose structures in other programming languages. Try it out.
By Andrew Gerrand
-------------------------------------------------------------
go panic recover 异常处理的更多相关文章
- Go语言异常处理defer\panic\recover
Go语言追求简洁优雅,所以,Go语言不支持传统的 try…catch…finally 这种异常,因为Go语言的设计者们认为,将异常与控制结构混在一起会很容易使得代码变得混乱.因为开发者很容易滥用异常, ...
- Go的异常处理 defer, panic, recover
Go语言追求简洁优雅,所以,Go语言不支持传统的 try…catch…finally 这种异常,因为Go语言的设计者们认为,将异常与控制结构混在一起会很容易使得代码变得混乱.因为开发者很容易滥用异常, ...
- [Go] 如何正确地 抛出 错误 和 异常(error/panic/recover)?
序言 错误 和 异常 是两个不同的概念,非常容易混淆.很多程序员习惯将一切非正常情况都看做错误,而不区分错误和异常,即使程序中可能有异常抛出,也将异常及时捕获并转换成错误.从表面上看,一切皆错误的思路 ...
- defer,panic,recover
Go语言不支持传统的 try…catch…finally 这种异常,因为Go语言的设计者们认为,将异常与控制结构混在一起会很容易使得代码变得混乱.因为开发者很容易滥用异常,甚至一个小小的错误都抛出一个 ...
- 探究 Go 源码中 panic & recover 有哪些坑?
转载请声明出处哦~,本篇文章发布于luozhiyun的博客: https://www.luozhiyun.com/archives/627 本文使用的go的源码1.17.3 前言 写这一篇文章的原因是 ...
- go语言defer panic recover用法总结
defer defer是go提供的一种资源处理的方式.defer的用法遵循3个原则 在defer表达式被运算的同时,defer函数的参数也会被运算.如下defer的表达式println运算的同时,其入 ...
- defer, panic, recover使用总结
1. defer : 延迟调用.多个defer,依次入栈,在函数即将退出时,依次出栈调用 package main import "fmt" func main() { defer ...
- Go panic recover
panic 1. 停止当前函数执行 2. 一直向上返回,执行每一层的defer 3. 如果没有遇到recover, 程序退出 recover 1. 仅在defer调用中使用 2. 获取panic的值 ...
- 闭包 panic recover
闭包=函数+外层变量的引用 recover必须搭配defer使用 defer一定要在可能引发panic的语句之前定义
随机推荐
- nginx提高加载静态文件速度
1.本来对于静态网页,我们不需要放在应用容器中,原因一时由于应用服务器是用来解析动态网页的,针对静态网页本来就性能不高,而且还会占用应用容器的资源,所以我们专门使用nginx用来解析静态网页. ...
- a 标签 download 和 target 不配合
发现一个奇怪的事,看代码 <a id="downloadAlink" target="_blank" href="http://www.baid ...
- Sass之二(进阶篇)
源码链接:http://pan.baidu.com/s/1o8M51hC 1. 数据类型 1.1 Number 数字类型,小数类型,带有像素单位的数字类型,全部都属于Number类型 Number类型 ...
- Struts2的默认拦截器执行顺序
我们在写Struts2的时候package属性默认都是差不多这样吧 <package name="packageName" namespace="/" e ...
- Hadoop伪分布安装详解(四)
目录: 1.修改主机名和用户名 2.配置静态IP地址 3.配置SSH无密码连接 4.安装JDK1.7 5.配置Hadoop 6.安装Mysql 7.安装Hive 8.安装Hbase 9.安装Sqoop ...
- 第九课——MySQL优化之索引和执行计划
一.创建索引需要关注什么? 1.关注基数列唯一键的数量: 比如性别,该列只有男女之分,所以性别列基数是2: 2.关注选择性列唯一键与行数的比值,这个比值范围在0~1之前,值越小越好: 其实,选择性列唯 ...
- 字符串与图片的Base64编码转换操作
//图片 转为 base64编码的文本 private void button1_Click(object sender, EventArgs e) { OpenFileDialog dlg = ne ...
- cloud native
什么是原生云(cloud native)应用? 原生云cloud-native应用的定义是:首先,应用系统应该与底层物理基础设施解耦.说白了,应用程序应该与操作系统等基础设施分离,不应该依赖Linux ...
- Pulsar
The Apache Software Foundation Announces Apache® Pulsar™ as a Top-Level Project : The Apache Softwar ...
- Django中间件如何处理请求
Django中间件 在http请求 到达视图函数之前 和视图函数return之后,django会根据自己的规则在合适的时机执行中间件中相应的方法. Django1.9版本以后中间件的执行流程 1. ...