• go语言的错误处理


    1、系统自己抛异常

    //go语言抛异常
    
    func test3_1()  {
    	l := [5] int {0,1,2,3,4}
    
    	var index int = 6
    
    	fmt.Println(l)
    	l[index] = 6
    
    }
    

    测试结果

    	//test3_1()
    	//panic这个关键字,这是系统自己抛的异常
    	//panic: runtime error: index out of range
    

     

    2、用户抛异常,使用panic关键字

    func test3_2(s float64) (m float64)  {
    	if s < 0 {
    		panic("该参数为半径,不能小于0")
    
    	}else {
    		return 3.14 * s * s
    	}
    }
    

    测试结果

    	//正常的参数,不会抛异常
    	//res := test3_2(3.6)
    	//fmt.Println(res)
    	//40.6944
    
    
    	//res := test3_2(-3.6)
    	//fmt.Println(res)
    	//panic: 该参数为半径,不能小于0
    

    3、使用defer+recover捕获函数执行过程中的异常并打印

    func test3_3() {
    	defer func() {
    		//这个recover会捕获函数执行的异常的错误信息,我们这里的例子是执行test3_2这个函数报错,使用panic抛出了异常,这里recover就会接受到这个异常,然后打印出来
    		err := recover()
    		if err != nil {
    			fmt.Println(err,"1111")
    		}
    	}()
    	test3_2(-2.34)
    	fmt.Println("这里是函数3")
    }
    

    测试结果

    	//test3_3()
    	//该参数为半径,不能小于0 1111
    

    我们看到“这里是函数3”这句话没有打印,因为上面的函数执行出错了,就直接执行defer语句了

    4、defer+recover用法2

    func test3_3() {
    	defer func() {
    		//这个recover会捕获函数执行的异常的错误信息,我们这里的例子是执行test3_2这个函数报错,使用panic抛出了异常,这里recover就会接受到这个异常,然后打印出来
    		err := recover()
    		if err != nil {
    			fmt.Println(err,"1111")
    		}
    	}()
    	test3_2(-2.34)
    	fmt.Println("这里是函数3")
    }
    
    func test3_4()  {
    	test3_3()
    	fmt.Println("这里是函数4")
    }
    

    测试结果

    	//test3_4()
    	//该参数为半径,不能小于0 1111
    	//这里是函数4
    

    这里打印了“这里是函数4”,主要是因为test3_3这个函数执行本身没有报错

    5、使用errors.NEW返回异常,并捕获打印

    //接受异常
    func test3_5(b float64) (m float64,e error)  {
    	if b < 0 {
    		e = errors.New("傻屌,半径不能为负数")
    		return
    	}else {
    		m = b * b *3.14
    		return
    	}
    }
    

    测试结果

    	m,e := test3_5(3.21)
    	fmt.Println(m,e)
    	//32.354874 <nil>
    
    	m1,e1 := test3_5(-3.21)
    	fmt.Println(m1,e1)
    	//0 傻屌,半径不能为负数
    

    Go 错误处理

    Go 语言通过内置的错误接口提供了非常简单的错误处理机制。

    error类型是一个接口类型,这是它的定义:

    type error interface {
        Error() string
    }
    

    我们可以在编码中通过实现 error 接口类型来生成错误信息。

    函数通常在最后的返回值中返回错误信息。使用errors.New 可返回一个错误信息:

    func Sqrt(f float64) (float64, error) {
        if f < 0 {
            return 0, errors.New("math: square root of negative number")
        }
        // 实现
    }
    

    在下面的例子中,我们在调用Sqrt的时候传递的一个负数,然后就得到了non-nil的error对象,将此对象与nil比较,结果为true,所以fmt.Println(fmt包在处理error时会调用Error方法)被调用,以输出错误,请看下面调用的示例代码:

    result, err:= Sqrt(-1)
    
    if err != nil {
       fmt.Println(err)
    }
    
    package main
    
    import (
        "fmt"
    )
    
    // 定义一个 DivideError 结构
    type DivideError struct {
        dividee int
        divider int
    }
    
    // 实现 `error` 接口
    func (de *DivideError) Error() string {
        strFormat := `
        Cannot proceed, the divider is zero.
        dividee: %d
        divider: 0
    `
        return fmt.Sprintf(strFormat, de.dividee)
    }
    
    // 定义 `int` 类型除法运算的函数
    func Divide(varDividee int, varDivider int) (result int, errorMsg string) {
        if varDivider == 0 {
                dData := DivideError{
                        dividee: varDividee,
                        divider: varDivider,
                }
                errorMsg = dData.Error()
                return
        } else {
                return varDividee / varDivider, ""
        }
    
    }
    
    func main() {
    
        // 正常情况
        if result, errorMsg := Divide(100, 10); errorMsg == "" {
                fmt.Println("100/10 = ", result)
        }
        // 当被除数为零的时候会返回错误信息
        if _, errorMsg := Divide(100, 0); errorMsg != "" {
                fmt.Println("errorMsg is: ", errorMsg)
        }
    
    }
    

    执行以上程序,输出结果为:

    100/10 =  10
    errorMsg is:  
        Cannot proceed, the divider is zero.
        dividee: 100
        divider: 0
    

    这里应该介绍一下 panic 与 recover,一个用于主动抛出错误,一个用于捕获panic抛出的错误。

    概念

    panic 与 recover 是 Go 的两个内置函数,这两个内置函数用于处理 Go 运行时的错误,panic 用于主动抛出错误,recover 用来捕获 panic 抛出的错误。

    • 引发panic有两种情况,一是程序主动调用,二是程序产生运行时错误,由运行时检测并退出。
    • 发生panic后,程序会从调用panic的函数位置或发生panic的地方立即返回,逐层向上执行函数的defer语句,然后逐层打印函数调用堆栈,直到被recover捕获或运行到最外层函数。
    • panic不但可以在函数正常流程中抛出,在defer逻辑里也可以再次调用panic或抛出panicdefer里面的panic能够被后续执行的defer捕获。
    • recover用来捕获panic,阻止panic继续向上传递。recover()defer一起使用,但是defer只有在后面的函数体内直接被掉用才能捕获panic来终止异常,否则返回nil,异常继续向外传递。

    例子1

    //以下捕获失败
    defer recover()
    defer fmt.Prinntln(recover)
    defer func(){
        func(){
            recover() //无效,嵌套两层
        }()
    }()
    
    //以下捕获有效
    defer func(){
        recover()
    }()
    
    func except(){
        recover()
    }
    func test(){
        defer except()
        panic("runtime error")
    }
    

    例子2

    多个panic只会捕捉最后一个:

    package main
    import "fmt"
    func main(){
        defer func(){
            if err := recover() ; err != nil {
                fmt.Println(err)
            }
        }()
        defer func(){
            panic("three")
        }()
        defer func(){
            panic("two")
        }()
        panic("one")
    }
    

    使用场景

    一般情况下有两种情况用到:

    • 程序遇到无法执行下去的错误时,抛出错误,主动结束运行。
    • 在调试程序时,通过 panic 来打印堆栈,方便定位错误。

    在看一个事例

    if result, errorMsg := Divide(100, 10); errorMsg == "" {
        fmt.Println("100/10 = ", result)
    }
    
    if _, errorMsg := Divide(100, 0); errorMsg != "" {
        fmt.Println("errorMsg is: ", errorMsg)
    }
    

    上面的事例等价于下面的事例

    result, errorMsg := Divide(100,10)
    if errorMsg == ""{
        fmt.Println("100/10 = ", result)
    }
    
    result, errorMsg = Divide(100,0)
    if errorMsg != ""{
        fmt.Println("errorMsg is: ", errorMsg)
    }
    

    fmt.Println 打印结构体的时候,会把其中的 error 的返回的信息打印出来

    type User struct {
       username string
       password string
    }
    
    func (p *User) init(username string ,password string) (*User,string)  {
       if ""==username || ""==password {
          return p,p.Error()
       }
       p.username = username
       p.password = password
       return p,""}
    
    func (p *User) Error() string {
          return "Usernam or password shouldn't be empty!"}
    }
    
    func main() {
       var user User
       user1, _ :=user.init("","");
       fmt.Println(user1)
    }
    

    结果如下

    Usernam or password shouldn't be empty!
    

     

    字符串操作

    package main
    
    import (
    	"fmt"
    	"strconv"
    )
    
    //字符串转换
    //Append系列函数,把整数等转换为字符串,添加到现有的字节数组中
    //Format系列函数,把其他类型的转换为字符串
    //Parse系列函数,把字符串转换为其他类型
    func main() {
    	str := make([]byte,0,100)
    
    	//10是十进制的意思
    	str = strconv.AppendInt(str,456,16)
    	str = strconv.AppendBool(str,false)
    	str = strconv.AppendQuote(str,"abc")
    	fmt.Println(string(str))
    }
    

      

  • 相关阅读:
    如何在Mac OS X上安装 Ruby运行环境
    CocoaPods安装和使用教程
    【Objective-C】07-自定义构造方法和description方法
    window cmd 命令大全 (order)
    vue methods 方法中 方法 调用 另一个方法。
    js ---- 函数防抖
    three.js 运行3D模型
    点击保存网页 (及页面的数据)
    js -- canvas img 封装
    js -- 分页功能
  • 原文地址:https://www.cnblogs.com/bainianminguo/p/10897228.html
Copyright © 2020-2023  润新知