第20讲 模拟Error
本讲基于视频实际讲解内容整理
一、本讲概述
Go语言不使用try-catch异常机制,而是通过函数返回值中的 error 类型来处理错误。本讲通过实际代码演示如何手动模拟错误(Error)的产生和处理。
二、error 类型
Go内置的 error 类型是一个接口类型,用于表示错误信息:
Go
// error 是一个接口
type error interface {
Error() string
}
使用 errors.New() 可以创建一个简单的error:
Go
import "errors"
err := errors.New("除数不能为零")
三、自定义函数模拟错误
3.1 定义结构体作为参数
老师在课程中演示了定义函数,接收struct作为参数,并根据条件返回错误:
Go
package main
import (
"errors"
"fmt"
)
// 定义结构体
type Calculator struct {
A int
B int
}
// 定义函数,接收struct参数,返回结果和error
func divide(c Calculator) (int, error) {
if c.B == 0 {
return 0, errors.New("除数不能为零")
}
return c.A / c.B, nil
}
3.2 手动模拟异常条件
老师演示了当满足某个条件时(如 B > 10),返回错误:
Go
func checkValue(c Calculator) (int, error) {
// 当B大于10时,模拟返回错误
if c.B > 10 {
return 0, errors.New("B的值不能超过10")
}
return c.A + c.B, nil
}
3.3 完整示例
Go
package main
import (
"errors"
"fmt"
)
type Calculator struct {
A int
B int
}
// 模拟错误:当B为0时返回error
func divide(c Calculator) (int, error) {
if c.B == 0 {
return 0, errors.New("除数不能为零")
}
return c.A / c.B, nil
}
// 模拟错误:当B大于10时返回error
func checkValue(c Calculator) (int, error) {
if c.B > 10 {
return 0, errors.New("B的值不能超过10")
}
return c.A + c.B, nil
}
func main() {
// 测试正常情况
c1 := Calculator{A: 10, B: 2}
result, err := divide(c1)
if err != nil {
fmt.Println("错误:", err)
} else {
fmt.Println("结果:", result) // 5
}
// 测试错误情况(B=0)
c2 := Calculator{A: 10, B: 0}
result, err = divide(c2)
if err != nil {
fmt.Println("错误:", err) // 错误: 除数不能为零
} else {
fmt.Println("结果:", result)
}
// 测试B>10的情况
c3 := Calculator{A: 5, B: 15}
result, err = checkValue(c3)
if err != nil {
fmt.Println("错误:", err) // 错误: B的值不能超过10
} else {
fmt.Println("结果:", result)
}
}
四、用下划线屏蔽error
老师演示了可以用下划线 _ 忽略(屏蔽)error返回值:
Go
// 忽略error(不推荐!)
result, _ := divide(Calculator{A: 10, B: 0})
fmt.Println(result) // 输出0,但不会报错
⚠️ 注意:忽略error是Go语法允许的,但非常不推荐在生产代码中使用。忽略error意味着程序可能在不正常的状态下继续运行,导致难以排查的bug。
五、匿名函数简介
老师在课程末尾简要介绍了匿名函数:没有名字的函数。
5.1 匿名函数的定义
Go
// 匿名函数:没有函数名
func(a int, b int) int {
return a + b
}
5.2 匿名函数的使用
Go
// 方式一:直接调用
result := func(a int, b int) int {
return a + b
}(10, 20)
fmt.Println(result) // 30
// 方式二:赋值给变量
add := func(a int, b int) int {
return a + b
}
fmt.Println(add(10, 20)) // 30
匿名函数常用于回调函数、闭包、Gin框架的路由处理等场景,后续课程会进一步讲解。
六、可变参数简介
老师还简要提到了可变参数,使用 ... 语法:
Go
// 可变参数:接收任意数量的int
func sum(nums ...int) int {
total := 0
for _, num := range nums {
total += num
}
return total
}
func main() {
fmt.Println(sum(1, 2, 3)) // 6
fmt.Println(sum(1, 2, 3, 4, 5)) // 15
}
可变参数将在第21讲中详细讲解。
七、Go错误处理模式总结
Go的错误处理模式与Java/C++的try-catch完全不同:
| 特性 | Java/C++ (try-catch) | Go (返回error) |
|---|---|---|
| 错误传递 | 抛出异常,自动向上传播 | 通过返回值手动检查 |
| 错误处理 | try-catch-finally | if err != nil |
| 忽略错误 | 难以忽略 | 可以用 _ 忽略(不推荐) |
| 性能 | 异常有性能开销 | 返回值几乎无开销 |
Go的标准错误处理模板
Go
result, err := someFunction()
if err != nil {
// 处理错误
fmt.Println("出错了:", err)
return
}
// 正常使用result
八、本讲小结
| 知识点 | 要点 |
|---|---|
| error类型 | Go内置接口类型,用于表示错误 |
| errors.New() | 创建error实例 |
| 模拟错误 | 在函数中根据条件返回error |
| 返回值约定 | 通常返回 (result, error) |
| 下划线_ | 可以忽略error(不推荐) |
| 匿名函数 | 没有名字的函数,func(参数){...} |
| 可变参数 | ...类型 语法,接收任意数量参数 |
| 错误处理 | if err != nil { ... } 模式 |
九、课后练习
- 定义一个
User结构体(Name, Age),编写函数验证Age是否合法(1-150),不合法返回error - 编写一个函数
parseInt(s string) (int, error),模拟Go的strconv.Atoi函数 - 调用上面的函数,分别处理正常和错误情况
- 尝试用
_忽略error,思考这样做的风险 - 编写一个匿名函数,实现两个数相乘的功能
- 编写一个可变参数函数
max(nums ...int) int,返回最大值