zoukankan      html  css  js  c++  java
  • 6.Go-错误,defer,panic和recover

    6.1.错误

       Go语言中使用builtin包下error接口作为错误类型

       Go语言中错误都作为方法/函数的返回值

       自定义错误类型

    //Learn_Go/main.go
    package main
    
    import (
    	"errors"
    	"fmt"
    )
    
    func demo(i,k int) (r int, e error)  {
    	if k == 0 {
    		e = errors.New("除数不能为0")
    		return
    	}
    	r = i/k
    	return
    }
    
    func main()  {
    	//result,error := demo(6,3)
    	result,e := demo(6,0)
    	if e != nil{
    		fmt.Println("执行错误,错误信息为:",e)   //执行错误,错误信息为: 除数不能为0
    		return
    	}
    	fmt.Println("执行成功,结果:",result)      //执行成功,结果: 2
    }
    

    6.2.defer

      Go语言中defer可以完成延迟功能,当前函数执行完成后执行defer功能

      defer最常用的就是关闭连接(数据库,文件等),可以打开连接后紧跟defer进行关闭

    (1)Go语言中defer无论写到哪里都是最后执行,不用非要把关闭代码写在最后

    //Learn_Go/main.go
    package main
    
    import "fmt"
    
    func main()  {
    	fmt.Println("打开连接")
    	//defer fmt.Println("关闭连接") 
    	defer func() {
    		fmt.Println("关闭连接")       //defer执行
    	}()
    	fmt.Println("进行操作")
    }
    
    //结果
    打开连接
    进行操作
    关闭连接
    

    (2)多个defer

      多重defer采用栈结构执行,先产生后执行

      在很多代码结构中都可能出现产生多个对象,而程序希望这些对象倒叙关闭,多个defer正好可以解决这个问题

    //Learn_Go/main.go
    package main
    
    import "fmt"
    
    func main()  {
    	fmt.Println("打开连接A")
    	defer fmt.Println("关闭连接A")
    	fmt.Println("打开连接B")
    	defer fmt.Println("关闭连接B")
    	fmt.Println("打开连接C")
    	defer fmt.Println("关闭连接C")
    	fmt.Println("进行操作")
    }
    
    //结果
    打开连接A
    打开连接B
    打开连接C
    进行操作
    关闭连接C
    关闭连接B
    关闭连接A
    

    (3)defer和return结合

       defer与return同时存在时,要把return理解成两条执行结合,一个指令是给返回值

       赋值,另一个指令返回跳出函数

       defer和return时整体执行顺序

    • 先给返回值赋值
    • 执行defer
    • 返回跳出函数

    (4)没有定义返回值接收变量,执行defer时返回值已经赋值

    //Learn_Go/main.go
    package main
    
    import "fmt"
    
    func demo() int {
    	i := 1
    	defer func() {
    		i = i + 2
    	}()
    	return i
    }
    
    func main() {
    	fmt.Println(demo())       //1
    }
    

    (5)声明接收返回值变量,执行defer时修改了返回值内容

    //Learn_Go/main.go
    package main
    
    import "fmt"
    
    func demo() (z int) {
    	i := 1
    	defer func() {
    		z = i + 2
    	}()
    	return
    }
    
    func main() {
    	fmt.Println(demo())       //3
    }
    

    6.3.panic

    panic是build中函数,当执行到panic后,终止剩余代码执行,并打印错误栈信息。

    //Learn_Go/main.go
    package main
    
    import "fmt"
    
    func main() {
    	fmt.Println("111")
    	panic("错误信息")
    	fmt.Println("222")
    }
    
    //结果
    111
    panic: 错误信息
    
    goroutine 1 [running]:
    main.main()
    C:/Users/86158/Desktop/Learn_Go/main.go:8 +0x82
    

    panic不是立即停止程序,defer还是执行的

    //Learn_Go/main.go
    package main
    
    import "fmt"
    
    func main() {
    	defer fmt.Println("执行defer的内容")
    	fmt.Println("111")
    	panic("错误信息")
    	fmt.Println("222")
    }
    
    //结果
    111
    执行defer的内容
    panic: 错误信息
    
    goroutine 1 [running]:
    main.main()
    C:/Users/86158/Desktop/Learn_Go/main.go:9 +0xdc
    

    6.4.recover

     recover()表示回复程序的panic(),让程序正常执行

        rcover()是和panic一样都是builtin中函数,可以接受panic的信息,恢复程序的正常执行

        recover()一般在defer内部,如果没有panic信息,返回nil;如果有panic,recover会把panic状态取消

    //Learn_Go/main.go
    package main
    
    import "fmt"
    
    func main() {
    	defer func() {
    		if error := recover();error != nil{
    			fmt.Println("panic为:", error)
    		}
    	}()
    	fmt.Println("111")
    	panic("出现了错误信息")
    	fmt.Println("222")
    }
    
    //结果
    111
    panic为: 出现了错误信息
    

    函数调用过程中panic和recover()

    • recover()只能恢复当前函数级或当前函数调用函数中的panic(),恢复后调用当前级别函数结束,但是调用此函数的函数可以继续执行
    • panic会一直向上传递,如果没有recover()则表示程序终止,但是碰见了recover(),recover()所在级别函数表示没有panic,panic就不会向上传递
    //Learn_Go/main.go
    package main
    
    import "fmt"
    
    func demo1()  {
    	fmt.Println("demo1上半部分")
    	demo2()
    	fmt.Println("demo1下半部分")
    }
    
    func demo2()  {
    	fmt.Println("demo2上半部分")
    	demo3()
    	fmt.Println("demo2下半部分")
    }
    
    func demo3()  {
    	fmt.Println("demo3上半部分")
    	panic("demo3中出现panic")
    	fmt.Println("demo3下半部分")
    }
    
    func main() {
    	fmt.Println("程序开始")
    	demo1()
    	fmt.Println("程序结束")
    }
    
    //结果
    程序开始
    demo1上半部分
    demo2上半部分
    demo3上半部分
    panic: demo3中出现panic
    

     demo3添加recover() 

    //Learn_Go/main.go
    package main
    
    import "fmt"
    
    func demo1()  {
    	fmt.Println("demo1上半部分")
    	demo2()
    	fmt.Println("demo1下半部分")
    }
    
    func demo2()  {
    	fmt.Println("demo2上半部分")
    	demo3()
    	fmt.Println("demo2下半部分")
    }
    
    func demo3()  {
    	defer func() {
    		recover()
    	}()
    	fmt.Println("demo3上半部分")
    	panic("demo3中出现panic")
    	fmt.Println("demo3下半部分")
    }
    
    func main() {
    	fmt.Println("程序开始")
    	demo1()
    	fmt.Println("程序结束")
    }
    
    //结果
    程序开始
    demo1上半部分
    demo2上半部分
    demo3上半部分
    demo2下半部分
    demo1下半部分
    程序结束
    

     demo2添加recover()

    //Learn_Go/main.go
    package main
    
    import "fmt"
    
    func demo1()  {
    	fmt.Println("demo1上半部分")
    	demo2()
    	fmt.Println("demo1下半部分")
    }
    
    func demo2()  {
    	defer func() {
    		recover()
    	}()
    	fmt.Println("demo2上半部分")
    	demo3()
    	fmt.Println("demo2下半部分")
    }
    
    func demo3()  {
    	fmt.Println("demo3上半部分")
    	panic("demo3中出现panic")
    	fmt.Println("demo3下半部分")
    }
    
    func main() {
    	fmt.Println("程序开始")
    	demo1()
    	fmt.Println("程序结束")
    }
    
    //结果
    程序开始
    demo1上半部分
    demo2上半部分
    demo3上半部分
    demo1下半部分
    程序结束
    
  • 相关阅读:
    mysq 日期相减
    说说时间观与时间管理——北漂18年(71)
    ionic之切换开关
    ionic之单选框
    SELECT ... LOCK IN SHARE MODE和SELECT ... FOR UPDATE locks在RR模式下可以看到最新的记录
    14.5.2.3 Consistent Nonlocking Reads 一致性非锁定读
    14.5.2.2 autocommit, Commit, and Rollback
    14.5.2 事务隔离级别
    对于唯一索引使用唯一条件搜索, InnoDB 只锁定找到的index record,不是它之前的区间
    mysql explain 解释
  • 原文地址:https://www.cnblogs.com/gaidy/p/11887140.html
Copyright © 2011-2022 走看看