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下半部分
    程序结束
    
  • 相关阅读:
    JAVA中拼音工具类
    USB接口不同颜色的作用
    java的反射机制使用方法
    利用FrameLayout+LinearLayout实现Android底部导航栏切换
    Andorid中如何读取文件
    JAVA中解压压缩包到制定文件夹工具方法
    Andorid中子线程更新主线程方法
    委托的定义使用
    Json的序列化和反序列化
    在线支付(模拟支付宝)
  • 原文地址:https://www.cnblogs.com/gaidy/p/11887140.html
Copyright © 2011-2022 走看看