一: panic和recover

作用:panic 用来主动抛出错误; recover 用来捕获 panic 抛出的错误。

概述: ,引发panic有两种情况 )程序主动调用panic函数 )程序产生运行时错误,由运行时检测并抛出 过程: ! 发生 panic 后,程序会从调用 panic的函数位置或发生panic 的地方立即返回,逐层向上执行函数的defer语句, 然后逐层打印函数调用堆栈,直到被 recover 捕获或运行到最外层函数而退出。 ! panic的参数是一个空接口类型 interface{},所以任意类型的变量都可以传递给 panic(xxx) ! panic 不但可以在函数正常流程中抛出,在 defer 逻辑里也可以再次调用 panic 或抛出 panic a defer 里面的 panic 能够被后续执行的 defer 捕获。 recover()用来捕获 panic,阻止panic继续向上传递recover()和defer一起使用 ,但是recover() 只  有在defer后面的函数体内被直接调用才能捕获panic终止异常否则返回 nil,异常继续向外传递
//这会获取失败
defer recover()
defer fmt.println(recover())
//嵌套两层也会获取失败
defer func() {
func(){
println("defer inner")
recover() //无效
}()
}

  以下场景会获取成功

package main
func f(){
defer func() {
println("defer inner")
recover()
}()
}
func except() {
recover()
}
func test(){
defer except()
panic("test panic")
}
func main() {
f()
except()
test()
}

  可以有多个panic被抛出,连续多个panic的场景只能出现在延迟调用里面,否则不会出现多个panic被抛出的场景。但只有最后一次panic能被捕获

package main

import "fmt"

func main(){
defer func() {
if err :=recover();err !=nil{
fmt.Println(err)
}
}()
  //只有最后一次panic调用被捕获
defer func() {
panic("first defer panic") //打印结构是这个
}()
defer func() {
panic("second defer panic")
}()
panic("main body panic")
}

  包中 in it 函数引发的 panic 只能在 in it 函数中捕获,在 main 中无法被捕获,原因是 in it
数先于 main 执行,函数并不能捕获内部新启动的 goroutine 所抛出的 panic 。

package main

import (
"fmt"
"time"
) func do() {
//这里并不能获取da函数中的panic
defer func() {
if err := recover();err != nil{
fmt.Println(err)
}
}()
go da()
go db()
time.Sleep(*time.Second)
}
func da(){
panic("panic da")
for i := ; i<; i++{
fmt.Println(i)
}
}
func db(){
for i := ; i<; i++{
fmt.Println(i)
}
}
func main() {
fmt.Println(do)
fmt.Println(da)
fmt.Println(db)
}

  示例

package main

import "fmt"

//系统抛异常
func test01() {
a := []int{, , , , }
//a[10] = 123
index :=
a[index] =
}
func main() {
//panic: runtime error: index out of range
//test01()
//test02()
//test03()
test04()
}
//自己抛异常
func test02() {
getCircleArea(-)
}
func getCircleArea(radius float32) (area float32) {
if radius < {
//抛异常
panic("半径不能为负数")
}
return 3.14 * radius * radius
}
func test03() {
//延时执行匿名函数
//延时到什么时候?要么正常结束,要么出异常
//recover()是复活的意思
defer func() {
if err := recover(); err != nil {
fmt.Println(err)
}
}()
//会报错
getCircleArea(-)
//下句话没有打印
fmt.Println("这里有没有执行?")
}
func test04() {
test03()
fmt.Println("GAME OVER")
}

返回异常

package main

import (
"errors"
"fmt"
) //算半径
func getCircleArea(radius float32) (ret float32, err error) {
if radius < {
//创建异常
err = errors.New("沙雕,半径不能为负数")
return
}
ret = 3.14 * radius * radius
return
} func main() {
ret, err := getCircleArea()
if err != nil {
fmt.Println(err)
} else {
fmt.Println("ret=", ret)
}
}

使用场景:

()程序遇到了无法正常执行下去的错误,主动调用 panic 函数结束程序运行
()在调试程序时,通过主动调用 panic 实现快速退出, panic 打印出的堆枝能够更快地定位错误。

为了保证程序的健壮性,需要主动在程序的分支流程上使用 recover()拦截运行时错误。

Go 提供了两种处理错误 方式,
一 种是借助 panic和 recover 的抛出捕获机制,
另一种使用error 错误类型

error:

go 语言内置错误接口类型
任何类型只要实现 error() string 方法,都可以传递 eηor接口类型变量。
Go 语言典型的错误处理方式是将error作为函数最后一个返回值 在调用函数
通过检测其返回的error值是否为nil来进行错误处理。
type  error interface{
Error() string
}

  

• 在多个返回值的函数中,error 通常作为函数最后一个返回值

• 如果一个函数返回error 类型变量 ,则先用if语句处理 error != nil 异常场景,正常逻辑放到 if 语句块的后面,
保持代码平坦。
• defer 吾句应该放到四判断的后面,不然有可能产生 panic
• 在错误逐级向上传递的过程中,错误信息应该不断地丰富和完善,而不是简单地抛出下层调用的错误。
这在错误日志分析 非常有用和友好。

错误和异常

广义上的错误: 发生非期望的行为。
狭义的错误:发生非期望的己知行为,这里的己知是指错误的类型是预料并定义好的。
异常: 发生非期待的未知行为。这里的未知是指错误的类型不在预先定义的范围内。异常又被称为未捕获的错误
( untrapped error )。程序在执行时发生未预先定义的错误,程序编译器和运行时都没有及时将其捕获处理。
而是由操作系统进行异常处理,比如 语言程序里面经常出现的 Segmentation Fault (段异常错误),这个就属
于异常范畴。

Go 是一门类型安全的语言,其运行时不 出现这种编译器和运行时都无法捕获的错 ,也就是说,
不会出现 untrapped error ,所以从这个角度来说, Go 语言不存在所谓的异常,出现的“异常”全是错误

Go 程序需要处理的这些错误可 分为两类
一类是运行时错误( runtime errors ),此类错误语言的运行时能够捕获,并采取措施一一隐式或显式地抛出 panic
一类是程序逻辑错误:程序执行结果不符合预期,但不会引发运行时错误
对于运行时错误程序员无法完全避免其发生,只能尽量减少其发生的概率,并在不影响程序主功能的分支流程上
“ rcover ”这些 panic,避免其因为一个panic引发整个程序的崩溃。

Go 对于错误提供了两种处理机制:

() 通过函数返回错误类型的值来处理错误。
() 通过 panic 打印程序调用枝,终止程序执行来处理错误。
所以对错误的处理也有两种方法,
一种是通过返回 个错误类型值来处理错误,
另一种是直接调用 panic 抛出错误,退出程序。
Go 是静态强类型语言,程序的大部分错误是可以在编译器检测到的,但是有些错误行为需要在运行期才能检测出来。
此种错误行为将导致程序异常退出 。其表现出的行为就和直接调用panic 一样 打印出函数调用技信息,并且终止程序执行
在实际的编程中,error和panic 的使用应该遵循如下三条原则:
)程序局部代码的执行结果不符合预期,但此种行为不是运行时错误范围内预定义的错
误,此种非期望的行为不会导致程序无法提供服务,此类场景应该使用函数返回 rror 类型变量
进行错误处理。
)程序执行过程中发生错误,且该种错误是运行时错误范围内预定义的错误,此时 Go
语言默认的隐式处理动作就是调用 panic ,如果此种 panic 发生在程序的分支流程不影响主要更
能,则可以在发生 panic 的程序分支上游处使用 recove 进行捕获,避免引发整个程序的崩溃。
)程序局部代码执行结果不符合预期,此种行为虽然不是运行时错误范围内预定义的错
误,但此种非期望的行为会导致程序无法继续提供服务,此类场景在代码中应该主动调用 panic
终止程序的执行。
进一步浓缩为两条规则
()程序发生的错误导致程序不能容错继续执行,此时程序应该主动调用 panic 或由运行
时抛出 panic
()程序虽然发生错误 但是程序能够容错继续执行,此时应该使用错误返回值的方式处理错误,
或者在可能发生运行时错误的非关键分支上使用 recover 捕获 panic

go语言之抛出异常的更多相关文章

  1. 05. Go 语言函数

    Go 语言函数 函数是组织好的.可重复使用的.用来实现单一或相关联功能的代码段,其可以提高应用的模块性和代码的重复利用率. Go 语言支持普通函数.匿名函数和闭包,从设计上对函数进行了优化和改进,让函 ...

  2. Swift 中异常抛出和四种异常处理

    在Swift中你可以像其他语言一样抛出异常处理异常,今天我们就详细地说说Swift中的异常抛出和处理. 在一开始我们要定义错误或者说是异常,Swift中的一些简单异常可以使用枚举定义,注意这个枚举要继 ...

  3. 一文读懂Lua元表

    元表 Lua语言中的每种类型的值都有一套可预见的操作集合.例如,我们可以将数字相加,可以连接字符串,还可以在表中插入键值对等,但是我们无法将两个表相加,无法对函数作比较,也无法调用一个字符串,除非使用 ...

  4. Go基础3:函数、结构体、方法、接口

    目录 1. 函数 1.1 函数返回值 同一种类型返回值 带变量名的返回值 函数中的参数传递 函数变量 1.2 匿名函数--没有函数名字的函数 在定义时调用匿名函数 将匿名函数赋值给变量 匿名函数用作回 ...

  5. 【Java面试题】22 JAVA语言如何进行异常处理,关键字:throws,throw,try,catch,finally分别代表什么意义?在try块中可以抛出异常吗?

    throws是获取异常throw是抛出异常try是将会发生异常的语句括起来,从而进行异常的处理,catch是如果有异常就会执行他里面的语句,而finally不论是否有异常都会进行执行的语句. thro ...

  6. 编译器开发系列--Ocelot语言2.变量引用的消解

    "变量引用的消解"是指确定具体指向哪个变量.例如变量"i"可能是全局变量i,也可能是静态变量i,还可能是局部变量i.通过这个过程来消除这样的不确定性,确定所引用 ...

  7. AVL树原理及实现(C语言实现以及Java语言实现)

    欢迎探讨,如有错误敬请指正 如需转载,请注明出处http://www.cnblogs.com/nullzx/ 1. AVL定义 AVL树是一种改进版的搜索二叉树.对于一般的搜索二叉树而言,如果数据恰好 ...

  8. javascript 核心语言笔记 5 - 语句

    表达式在 JavaScript 中是短语(phrases),那么语句(statements)就是 JavaScript 整句或命令,语句以分号结束.表达式计算出一个值,语句用来执行以使某件事情发生 表 ...

  9. Module Zero之语言管理

    返回<Module Zero学习目录> 概览介绍 如何开启 管理语言 管理本地化文本 概览介绍 ABP定义了一个健壮的UI本地化系统,它可用于服务端和客户端.它允许在不同的资源中(Reso ...

随机推荐

  1. 集合:List接口的实现类(ArrayList、LinkedList、Vector)

    1.List接口 (1)特点 有序(插入和取出的顺序相等,因为有一个整数索引记录了元素的插入的位置) 允许有重复的元素(调用equals方法返回true,允许有多个null) @Test public ...

  2. Python高性能HTTP客户端库requests的使用

    Python中有许多HTTP客户端.使用最广泛且最容易的是requests. 持续连接 很多人学习python,不知道从何学起.很多人学习python,掌握了基本语法过后,不知道在哪里寻找案例上手.很 ...

  3. spring data jpa 代码生成!!(精华帖)

    通过数据库动态生成自己想要生成的各种模板,需要了解grovery. view -> Tool Windows -> Database + -> Data source -> M ...

  4. JS 图片跟随鼠标移动案例

    css代码 img { position: absolute; /* top: 2px; */ width: 50px; height: 50px; } HTML代码 <img src=&quo ...

  5. javascript逻辑运算与循环笔记

        短路运算(逻辑中断)     1.短路运算的原理:当有多个表达式(值)时,左边的表达式值可以确定结果的时候就不再继续运算右边的表达式的值     2.逻辑与 &&     如果 ...

  6. puppet master/agent

    puppet master/agent 配置 安装 master: yum install puppet-server agent: yum install puppet 自动签名 puppet的ma ...

  7. 使用webgl(three.js)创建科技版3D机房,3D机房微模块详细介绍(升级版三)—— 1

    上节课已经详细描述了微模块机房的实现过程,文章地址(https://www.cnblogs.com/yeyunfei/p/10484241.html) 紧接着上节课的内容 我们这节可来详细讲解科技版机 ...

  8. SkyWalking 搭建及简单使用(Linux)

    1.需求 公司项目采用微服务的架构,服务很多,人工监控是不可能的,项目的访问量很大,想通过日志查找某个方法中性能的问题也是非常困难的.但是系统的性能问题是不能忽视的.系统性能检测的问题如鲠在喉,经过长 ...

  9. CornerNet

    论文 CornerNet: Detecting Objects as Paired Keypoint

  10. Linux学习笔记 一 第二章 Linux系统安装

    Linux系统安装 一.首先安装VMware 虚拟机 下载网址:https://www.vmware.com/cn/products/workstation-pro/workstation-pro-e ...