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 抛出的错误。

go语言的错误处理详解编程语言

  • 引发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)) 
} 

  

原创文章,作者:ItWorker,如若转载,请注明出处:https://blog.ytso.com/20922.html

(0)
上一篇 2021年7月19日
下一篇 2021年7月19日

相关推荐

发表回复

登录后才能评论