V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
haicoderibai
V2EX  ›  推广

说说 Golang 异常捕获

  •  
  •   haicoderibai · 2020-11-16 12:53:38 +08:00 · 689 次点击
    这是一个创建于 1265 天前的主题,其中的信息可能已经有所发展或是发生改变。

    原文地址:嗨客网

    Golang panic recover 详解

    Golang panic recover 详解教程

    Go 语言 中的 panic 的作用就是抛出一条错误信息,从它的参数类型可以看到它可以抛出任意类型的错误信息。在函数执行过程中的某处调用了 panic,则立即抛出一个错误信息,同时函数的正常执行流程终止,但是该函数中 panic 之前定义的 defer 语句将被依次执行。之后该 goroutine 立即停止执行。

    recover() 用于将 panic 的信息捕捉。recover 必须定义在 panic 之前的 defer 语句中。在这种情况下,当 panic 被触发时,该 goroutine 不会简单的终止,而是会执行在它之前定义的 defer 语句。

    Golang panic recover 详解

    语法

    defer func() {
    	if err := recover(); err != nil {
    		fmt.Println("Panic recover, Err =", err, "Stack =", string(debug.Stack()))
    	}
    }()
    

    说明

    当发生异常时,我们使用了 recover 恢复,并打印了错误信息和堆栈信息。

    panic 无 recover

    说明

    如果在一个函数中,遇到了 panic,并且没有 recover,那么程序直接终止

    案例

    package main
    
    import (
    	"fmt"
    )
    
    func main() {
    	fmt.Println("嗨客网(www.haicoder.net)")
    
    	var hMap map[string]string
    	hMap["name"] = "haicoder"
    }
    

    此时,我们运行程序,控制台输出如下:

    我们给一个空 map 赋值,结果程序发生了 panic,因为,我们没有 recover,因此,程序异常终止了。

    panic 有 recover

    说明

    如果在一个函数中,遇到了 panic,并且有 recover,那么程序不会终止

    案例

    package main
    
    import (
    	"fmt"
    )
    
    func main() {
    	fmt.Println("嗨客网(www.haicoder.net)")
    
    	defer func() {
    		if err := recover(); err != nil {
    			fmt.Println("Panic recover, Err =", err)
    		}
    	}()
    
    	var hMap map[string]string
    	hMap["name"] = "haicoder"
    
    	fmt.Println("Over")
    }
    

    此时,我们运行程序,控制台输出如下:

    这次,在函数里面,我们使用了 recover 捕获错误,我们看到,此时程序不再报错了,并且,异常下面的代码不会再继续执行了。

    子函数 panic 有 recover

    说明

    子函数 panic,并且有 recover,不影响主函数的执行

    案例

    package main
    
    import (
    	"fmt"
    )
    
    func main() {
    	fmt.Println("嗨客网(www.haicoder.net)")
    
    	fmt.Println(fun1(10, 5))
    	fmt.Println(fun1(10, 0))
    	fmt.Println(fun1(10, 2))
    
    	fmt.Println("Over")
    }
    
    func fun1(a, b int)int{
    	defer func() {
    		if err := recover(); err != nil {
    			fmt.Println("Panic recover, Err =", err)
    		}
    	}()
    
    	return a / b
    }
    

    此时,我们运行程序,控制台输出如下:

    我们在子函数里面,发生了 panic,并且使用了 recover,此时在调用函数里面,调用子函数,并不影响主函数的执行。

    子函数 panic 主函数 recover

    说明

    子函数 panic,主函数 recover,程序不会终止执行

    案例

    package main
    
    import (
    	"fmt"
    )
    
    func main() {
    	fmt.Println("嗨客网(www.haicoder.net)")
    
    	defer func() {
    		if err := recover(); err != nil {
    			fmt.Println("Panic recover, Err =", err)
    		}
    	}()
    
    	fmt.Println(fun1(10, 5))
    	fmt.Println(fun1(10, 0))
    	fmt.Println(fun1(10, 2))
    
    	fmt.Println("Over")
    }
    
    func fun1(a, b int)int{
    	return a / b
    }
    

    此时,我们运行程序,控制台输出如下:

    我们在子函数里面,发生了 panic,并且在主函数使用了 recover,此时程序不会终止执行。

    子协程 panic 主函数 recover

    说明

    子协程 panic,主函数 recover,程序会终止执行

    案例

    package main
    
    import (
    	"fmt"
    	"time"
    )
    
    func main() {
    	fmt.Println("嗨客网(www.haicoder.net)")
    
    	defer func() {
    		if err := recover(); err != nil {
    			fmt.Println("Panic recover, Err =", err)
    		}
    	}()
    
    	go fun1(10, 5)
    	go fun1(10, 0)
    	go fun1(10, 2)
    
    	fmt.Println("Over")
    	time.Sleep(10*time.Second)
    }
    
    func fun1(a, b int)int{
    	return a / b
    }
    

    此时,我们运行程序,控制台输出如下:

    我们在子协程里面,发生了 panic,并且在主函数使用了 recover,此时程序会终止执行。

    子协程 panic 子协程 recover

    说明

    子协程 panic,子协程 recover,不影响主函数执行

    案例

    package main
    
    import (
    	"fmt"
    	"time"
    )
    
    func main() {
    	fmt.Println("嗨客网(www.haicoder.net)")
    
    	go fun1(10, 5)
    	go fun1(10, 0)
    	go fun1(10, 2)
    
    	fmt.Println("Over")
    	time.Sleep(10*time.Second)
    }
    
    func fun1(a, b int)int{
    	defer func() {
    		if err := recover(); err != nil {
    			fmt.Println("Panic recover, Err =", err)
    		}
    	}()
    
    	return a / b
    }
    

    此时,我们运行程序,控制台输出如下:

    在主函数里面,子协程发生了 panic,并且使用了 recover,不影响主函数的继续执行。

    Golang panic recover 总结

    golang 中的 defer 的使用可以总结为,如果 panic 和 recover 发生在同一个协程,那么 recover 是可以捕获的,如果 panic 和 recover 发生在不同的协程,那么 recover 是不可以捕获的。

    原文地址:嗨客网

    更多文章,可以关注下方公众号:

    嗨客网

    目前尚无回复
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   2370 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 34ms · UTC 07:09 · PVG 15:09 · LAX 00:09 · JFK 03:09
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.