Go语言第十四课 错误与异常

概念

在Go里面错误与异常是两个概念

错误是可以预期的,错误发生后,程序应该可以自行处理。

异常是不可预期的,异常的发生常常会导致程序崩溃。

关于错误

内建类型error

package main

import (
	"fmt"
)

func main() {
	a, err := testError(10, 0)
	if err != nil {
		fmt.Println(err.Error())
	} else {
		fmt.Println(a)
	}
}

func testError(a int, b int) (result float32, err error) {
	if b == 0 {
		return 0, fmt.Errorf("fuck error")
	}
	return float32(a) / float32(b), nil
}

结果

fuck error

这是一个很经典的例子。这个例子利用的正是内建的error类型向外界传递函数执行出错的信息。

自定义错误类型

实际上内建类型error是一个接口,实现自定义错误其实只需要实现Error()string接口即可

package main

import (
	"fmt"
)

func main() {
	a, err := testError(10, 0)
	if err != nil {
		fmt.Println(err.Error())
	} else {
		fmt.Println(a)
	}
}

func testError(a int, b int) (result float32, err error) {
	if b == 0 {
		return 0, err_mul{float32(a), float32(b)}
	}
	return float32(a) / float32(b), nil
}

type err_mul struct {
	record_a float32
	record_b float32
}

func (this err_mul) Error() string {
	return fmt.Sprintf("fuck error %f/%f", this.record_a, this.record_b)
}

结果

fuck error 10.000000/0.000000

关于异常

异常不是错误,错误是程序员可预期的,程序员自然也可以处理的。异常是程序员无法预期的,往往会导致程序崩溃等不可恢复性错误。

关于defer关键字

package main

import "fmt"

func main() {
fmt.Println(testDefer(1))
fmt.Println(testDefer(0))
fmt.Println(testDefer(2))
}

func testDefer(a int) float32 {
fmt.Println("start")
defer fmt.Println("defer 1")
fmt.Println("run 1 step")
defer fmt.Println("defer 2")
b := 1 / a
defer fmt.Println("defer 3")
return float32(b)
}

结果:

start
run 1 step
defer 3
defer 2
defer 1
1
start
run 1 step
defer 2
defer 1
panic: runtime error: integer divide by zero

这种结果充分说明了defer关键字的作用:

1、defer只会在函数运行结束或者运行出错后才会运行。这两种情况可归纳为函数运行结束。即:

defer会在函数运行结束后开始运行

2、defer会从函数运行结束的地方开始倒序运行,这里的函数运行结束的地方可能是函数结尾,可能是函数异常退出的地方。即:

defer会从函数运行结束处倒序运行

defer机制通常用于关闭IO等操作。这样就可以避免IO异常情况下无法关闭而导致的错误。

关于panic内建函数

这是一个抛出异常的内建函数。异常通常来自运行时(例如做1/0的操作),但是程序员也可以手动抛出。

package main

import "fmt"

func main() {
	testPanic()
}

func testPanic() {
	defer fmt.Println("defer 1")
	fmt.Println("run 1 step")
	panic(fmt.Errorf("this is fuck error"))
	fmt.Println("run 2 step")
}

结果

run 1 step
defer 1

panic: this is fuck error

可以看到,虽然做了defer善后,但是程序还是崩溃了。

通常,我们不应该在程序出现panic崩溃之后做任何处理,因为发程panic意味着程序出现了严重问题,最好让其强行终止。

但是我们也可以尝试拯救一下(虽然不建议这样做),这就需要用到recover

内建函数recover

recover可以处理panic,类似于try/cache中的cache

package main

import (
	"fmt"
)

func main() {
	fmt.Printf("result is %d\n", testPanic(0))
	fmt.Printf("result is %d\n", testPanic(1))
}

func testPanic(a int) int {
	defer func() {
		rec := recover()
		if rec != nil {
			p := rec.(error)
			fmt.Println("has error -> " + p.Error())
		} else {
			fmt.Println("no error")
		}
	}()
	fmt.Println("run 1 step")
	if a == 1 {
		panic(fmt.Errorf("fuck error"))
	}
	fmt.Println("run 2 step")
	return 1
}

结果:

run 1 step
run 2 step
no error
result is 1
run 1 step
has error -> fuck error
result is 0






猜你喜欢

转载自blog.csdn.net/yongyu_it/article/details/80853902