defer  

  defer是go提供的一种资源处理的方式。defer的用法遵循3个原则

  • 在defer表达式被运算的同时,defer函数的参数也会被运算。如下defer的表达式println运算的同时,其入参i也会被运算,结果为初始化值0,故defer调用中会打印“0”
1 func a() {
2 i := 0
3 defer fmt.Println(i)
4 i++
5 return
6 }
  • defer函数在一个函数return之后遵循后进先出的调用原则,如下打印结果为3210
func b() {
for i := 0; i < 4; i++ {
defer fmt.Print(i)
}
}
  • defer函数可能会读取并赋值给所在函数的返回值,如下返回值为2
func c() (i int) {
defer func() { i++ }()
return 1
}

  

针对上述的第三点有如下三种情况:

例1:
func f() (result int) {
defer func() {
result++
}()
return 0
}
例2:
func f() (r int) {
t := 5
defer func() {
t = t + 5
}()
return t
}
例3:
func f() (r int) {
defer func(r int) {
r = r + 5
}(r)
return 1
}

函数返回的过程是这样的:先给返回值赋值,然后再调用defer表达式,最后才是返回到调用函数中

先看例1,它可以改写成这样:

func f() (result int) {
result = 0 //return语句不是一条原子调用,return xxx其实是赋值+ret指令
func() { //defer被插入到return之前执行,也就是赋返回值和ret指令之间
result++
}()
return
}

所以这个返回值是1。

再看例2,它可以改写成这样:

func f() (r int) {
t := 5
r = t //赋值指令
func() { //defer被插入到赋值与返回之间执行,这个例子中返回值r没被修改过
t = t + 5
}
return //空的return指令
}

所以这个的结果是5。

最后看例3,它改写后变成:

func f() (r int) {
r = 1 //给返回值赋值
func(r int) { //这里改的r是传值传进去的r,不会改变要返回的那个r值
r = r + 5
}(r)
return //空的return
}

  所以这个例子的结果是1。

panic和recover

panic和recover的使用需要遵循以下原则:

  1. defer 需要放在 panic 之前定义,另外recover只有在 defer 调用的函数中才有效。
  2. recover处理异常后,逻辑并不会恢复到 panic 那个点去,函数跑到 defer 之后的那个点.
  3. 多个 defer 会形成 defer 栈,后定义的 defer 语句会被最先调用

使用recover捕获程序中的错误的用法如下

package main

import (
"fmt"
"time"
) func main() {
f()
fmt.Println("end")
} func f() {
  defer func() {      //必须要先声明defer,否则不能捕获到panic异常
    fmt.Println("defer start")
    if err := recover(); err != nil {
      fmt.Println(err) //这里的err其实就是panic传入的内容,"bug"
    }
    fmt.Println("defer end")
  }()
  for {
    fmt.Println("func begin")
    a := []string{"a", "b"}
    fmt.Println(a[3])    // 越界访问,肯定出现异常
    panic("bug")     // 上面已经出现异常了,所以肯定走不到这里了。
    fmt.Println("func end") // 不会运行的.
    time.Sleep(1 * time.Second)
  }
}

输出结果如下

 func begin
defer start
runtime error: index out of range
defer end
end

注:上述代码摘自如下参考的文档

参考:

Defer, Panic, and Recover

关于golang的panic recover异常错误处理

defer关键字

go语言defer panic recover用法总结的更多相关文章

  1. Go语言异常处理defer\panic\recover

    Go语言追求简洁优雅,所以,Go语言不支持传统的 try…catch…finally 这种异常,因为Go语言的设计者们认为,将异常与控制结构混在一起会很容易使得代码变得混乱.因为开发者很容易滥用异常, ...

  2. defer,panic,recover

    Go语言不支持传统的 try…catch…finally 这种异常,因为Go语言的设计者们认为,将异常与控制结构混在一起会很容易使得代码变得混乱.因为开发者很容易滥用异常,甚至一个小小的错误都抛出一个 ...

  3. Go的异常处理 defer, panic, recover

    Go语言追求简洁优雅,所以,Go语言不支持传统的 try…catch…finally 这种异常,因为Go语言的设计者们认为,将异常与控制结构混在一起会很容易使得代码变得混乱.因为开发者很容易滥用异常, ...

  4. defer, panic, recover使用总结

    1. defer : 延迟调用.多个defer,依次入栈,在函数即将退出时,依次出栈调用 package main import "fmt" func main() { defer ...

  5. Go语言 异常panic和恢复recover用法

    Go语言 异常panic和恢复recover用法 背景:Go语言追求简洁优雅,所以,Go语言不支持传统的 try…catch…finally 这种异常,因为Go语言的设计者们认为,将异常与控制结构混在 ...

  6. Golang 入门系列(十四)defer, panic和recover用法

    以前讲过golang 的基本语法.但是,只是讲了一些基础的语法,感兴趣的可以看看以前的文章,https://www.cnblogs.com/zhangweizhong/category/1275863 ...

  7. go panic recover 异常处理

    Go语言追求简洁优雅,所以,Go语言不支持传统的 try…catch…finally 这种异常,因为Go语言的设计者们认为,将异常与控制结构混在一起会很容易使得代码变得混乱.因为开发者很容易滥用异常, ...

  8. go语言 defer 高级

    go语言defer语句的用法 defer的语法 defer后面必须是函数调用语句,不能是其他语句,否则编译器会出错. package main import "log" func ...

  9. [日常] Go语言圣经-Panic异常,Recover捕获异常习题

    Go语言圣经-Panic异常1.当panic异常发生时,程序会中断运行,并立即执行在该goroutine中被延迟的函数(defer 机制)2.不是所有的panic异常都来自运行时,直接调用内置的pan ...

随机推荐

  1. dfs练习

    不给提示,练习. 题意: 蒜头的数学实在是太差了,于是老师把他关到小黑屋让他闭门修炼.老师跟他一张纸,上面一排写着1, 2, 3...N这N个数,中间用空白分隔.老师让他在空白处填上加号或者减号.他让 ...

  2. nyoj737 石子合并(一) 区间DP

    dp[x][y]表示合并[x, y]区间的石子的最小花费,将区间长度递增枚举即可. AC代码: #include<cstdio> #include<algorithm> usi ...

  3. 转:彻底搞清referrer和origin

    在http协议中有这两个字段,之前一直隐隐约约的觉得是,一种标记请求来源的方法(的确是),但是更细致的对这两个字段的比较却没有一个清楚的认识. referrer 到底是referer还是referre ...

  4. linux权限归属及特殊权限设置

    访问权限:读取:允许查看内容 -read写入:允许修改内容 -write可执行:允许运行和切换 -excute(以上三点rwx共同决定最终权限)归属关系:所有者:拥有此文件/目录的用户 -user所属 ...

  5. dojo之dojox/data/CsvStore初始化

    dojo之dojox/data/CsvStore初始化 1.var csvStore = new dojox.data.CsvStore({url:"student.csv"}); ...

  6. 如何获取Linux-gate.so.1动态库

    前面"Linux应用程序Helloworld入门"已经提到在Linux下每个可执行文件都依赖于几个最为基本的动态库,其中一个就是linux-gate.so.1. 从上面ldd给出的 ...

  7. Rweibo , wordcloud

    利用Rweibo ,wordcloud做词云 #导入需要的包,不存在则下载 require(Rweibo) #必须先调用rJava不然Rwordseg 无法使用 library(rJava) requ ...

  8. 基于am3358的lcd输出

    /*#include<stdio.h> */ #include <unistd.h> #include <stdio.h> #include <stdlib. ...

  9. Caused by: java.lang.ClassNotFoundException: flex.messaging.io.BeanProxy

    1.错误描述 2014-7-13 1:34:46 org.apache.catalina.startup.HostConfig undeploy 信息: Undeploying context [/b ...

  10. ubuntu16.04搭建ftp服务器

    因为习惯了vs进行开发,所以对于Linux的代码编辑开发都在vs里面进行,通常我们都是ssh远程登录到Linux,使用ftp或者sftp共享Linux目录里面的文件方便对文件的共享,这里介绍一下在ub ...