26.异常处理
Golang 没有结构化异常,使用 panic 抛出错误,recover 捕获错误。
Go中可以抛出一个panic的异常,然后在defer中通过recover捕获这个异常,然后正常处理。
1.利用recover处理panic指令,defer 必须放在 panic 之前定义,另外 recover 只有在 defer 调用的函数中才有效。否则当panic时,recover无法捕获到panic,无法防止panic扩散。
2.recover 处理异常后,逻辑并不会恢复到 panic 那个点去,函数跑到 defer 之后的那个点。
3.多个 defer 会形成 defer 栈,后定义的 defer 语句会被最先调用。
package main
import (
"fmt"
)
func except() {
fmt.Println(recover())
}
func test() {
defer except()
panic("test panic")
}
func main() {
test() //text panic
}
错误结果
标准库 errors.New 和 fmt.Errorf 函数用于创建实现 error 接口的错误对象。通过判断错误对象实例来确定具体错误类型。
package main
import (
"errors"
"fmt"
)
var ErrDivByZero = errors.New("division by zero")
func div(x, y int) (int, error) {
if y == 0 {
return 0, ErrDivByZero
}
return x / y, nil
}
func main() {
defer func() {
fmt.Println(recover())
}()
switch z, err := div(10, 0); err {
case nil:
println(z)
case ErrDivByZero:
panic(err)
}
}
实现try catch
package main
import "fmt"
func Try(fun func(), handler func(interface{})) {
defer func() {
if err := recover(); err != nil {
handler(err)
}
}()
fun()
}
func main() {
Try(func() {
panic("test panic")
}, func(err interface{}) {
fmt.Println(err)
})
}
如何区别使用 panic 和 error 两种方式?
惯例是:导致关键流程出现不可修复性错误的使用 panic,其他使用 error。
27.单元测试
在Go语言中,单元测试是通过编写函数来实现的,这些函数使用Go标准库中的"testing"包进行测试。下面是一个简单的示例,演示如何编写和运行Go的单元测试:
// 定义一个包
package mypackage
// 定义一个被测试的函数
func Add(a, b int) int {
return a + b
}
// 编写单元测试函数
func TestAdd(t *testing.T) {
result := Add(2, 3)
expected := 5
if result != expected {
t.Errorf("Add(2, 3) returned %d, expected %d", result, expected)
}
}
在上面的示例中,我们定义了一个名为Add的函数,它接受两个整数并返回它们的和。然后,我们编写了一个名为TestAdd的测试函数,它使用testing.T类型的参数来报告测试结果。在测试函数中,我们调用Add函数,并将其返回值与预期值进行比较。如果结果不符合预期,我们使用t.Errorf函数输出错误信息。
要运行这个测试,可以使用go test命令。在终端中,进入包含测试文件的目录,并运行以下命令:
go test
如果测试成功通过,将不会有任何输出。如果测试失败,将输出相应的错误信息。
go test命令是一个按照一定约定和组织的测试代码的驱动程序。在包目录内,所有以_test.go为后缀名的源代码文件都是go test测试的一部分,不会被go build编译到最终的可执行文件中。
| 类型 | 格式 | 作用 |
|---|---|---|
| 测试函数 | 函数名前缀为Test | 测试程序的一些逻辑行为是否正确 |
| 基准函数 | 函数名前缀为Benchmark | 测试函数的性能 |
| 示例函数 | 函数名前缀为Example | 为文档提供示例文档 |
被测试文件muti.go
package TestDemo
import "errors"
func Division(a, b float64) (float64, error) {
if b == 0 {
return 0, errors.New("除数不能为0")
}
return a / b, nil
}
测试文件multi_test.go
package TestDemo
import "testing"
func Test_hello(t *testing.T) {
if division, err := Division(6, 2); division != 3 || err != nil {
t.Error("函数没通过")
} else {
t.Log("通过了")
}
}
func Test_Division_2(t *testing.T) {
t.Error("NONO")
}
go test -v (-v也会显示log信息,不加-v 通过了这句话不会打印出来)