- 实现用户注册、登录、JWT令牌认证功能 - 集成Gin、GORM、Viper、Zap等框架 - 添加密码加密、数据库操作、中间件等完整功能 - 配置多环境支持、日志轮转、CORS处理 - 创建完整的项目结构和配置文件体系
123 lines
3.1 KiB
Go
123 lines
3.1 KiB
Go
package main
|
||
|
||
import (
|
||
"errors"
|
||
"fmt"
|
||
"os"
|
||
)
|
||
|
||
// ========== 1. 自定义错误 + fmt.Errorf 封装 ==========
|
||
func divide(a, b float64) (float64, error) {
|
||
if b == 0 {
|
||
// 使用 fmt.Errorf 包装原始错误,添加上下文
|
||
return 0, fmt.Errorf("divide by zero: cannot divide %.2f by %.2f", a, b)
|
||
}
|
||
return a / b, nil
|
||
}
|
||
|
||
// 更复杂的错误链(Go 1.13+ 支持 %w)
|
||
var ErrNegativeInput = errors.New("input must be non-negative")
|
||
|
||
func sqrt(x float64) (float64, error) {
|
||
if x < 0 {
|
||
// 使用 %w 包装错误,支持 errors.Is 和 errors.As
|
||
return 0, fmt.Errorf("invalid input for sqrt: %w", ErrNegativeInput)
|
||
}
|
||
return x * x, nil // 注意:这里故意写成平方,方便测试
|
||
}
|
||
|
||
// ========== 2. defer 的典型用途 ==========
|
||
func readFile(filename string) error {
|
||
fmt.Println("尝试打开文件:", filename)
|
||
file, err := os.Open(filename)
|
||
if err != nil {
|
||
return fmt.Errorf("无法打开文件 %s: %w", filename, err)
|
||
}
|
||
// defer 确保文件在函数退出前关闭(即使 panic)
|
||
defer func() {
|
||
fmt.Println("defer: 关闭文件")
|
||
file.Close()
|
||
}()
|
||
|
||
// 模拟读取
|
||
fmt.Println("文件已打开,正在读取...")
|
||
return nil
|
||
}
|
||
|
||
// ========== 3. panic 与 recover ==========
|
||
func riskyFunction(n int) {
|
||
defer func() {
|
||
if r := recover(); r != nil {
|
||
fmt.Printf("recover 捕获到 panic: %v\n", r)
|
||
}
|
||
}()
|
||
if n < 0 {
|
||
panic("n 不能为负数!")
|
||
}
|
||
fmt.Println("riskyFunction 正常执行,n =", n)
|
||
}
|
||
|
||
// recover 只在 defer 中有效!
|
||
func noRecover() {
|
||
// ❌ 这样写无法捕获 panic
|
||
recover()
|
||
panic("不会被捕获")
|
||
}
|
||
|
||
// ========== 4. 综合示例:安全计算 ==========
|
||
func safeCompute(a, b float64) {
|
||
defer fmt.Println("safeCompute 结束\n---")
|
||
|
||
fmt.Printf("计算 %.2f / %.2f\n", a, b)
|
||
result, err := divide(a, b)
|
||
if err != nil {
|
||
fmt.Println("错误:", err)
|
||
return
|
||
}
|
||
fmt.Printf("结果: %.2f\n", result)
|
||
|
||
fmt.Println("尝试对结果开方(实际是平方)")
|
||
sq, err := sqrt(result)
|
||
if err != nil {
|
||
if errors.Is(err, ErrNegativeInput) {
|
||
fmt.Println("检测到特定错误:输入为负")
|
||
}
|
||
fmt.Println("sqrt 错误:", err)
|
||
return
|
||
}
|
||
fmt.Printf("平方结果: %.2f\n", sq)
|
||
}
|
||
|
||
// ========== 主函数 ==========
|
||
func main() {
|
||
fmt.Println("=== 1. 基本 error 处理 ===")
|
||
safeCompute(10, 2)
|
||
safeCompute(10, 0) // 触发除零错误
|
||
|
||
fmt.Println("\n=== 2. defer 文件操作 ===")
|
||
fileErr := readFile("/nonexistent/file.txt") // 文件不存在,触发错误
|
||
if fileErr != nil {
|
||
fmt.Println("文件操作错误:", fileErr)
|
||
}
|
||
fileErr2 := readFile("/etc/hostname") // 存在的文件(Linux 系统通常有)
|
||
if fileErr2 != nil {
|
||
fmt.Println("文件操作错误:", fileErr2)
|
||
}
|
||
fmt.Println("\n=== 3. panic 与 recover ===")
|
||
riskyFunction(5)
|
||
riskyFunction(-1) // 触发 panic,但被 recover 捕获
|
||
|
||
fmt.Println("\n=== 4. 错误封装与识别 ===")
|
||
_, err := sqrt(-4)
|
||
if err != nil {
|
||
fmt.Println("原始错误信息:", err)
|
||
// 使用 errors.Is 判断是否包含特定错误
|
||
if errors.Is(err, ErrNegativeInput) {
|
||
fmt.Println("✅ 成功识别自定义错误 ErrNegativeInput")
|
||
}
|
||
}
|
||
|
||
// ⚠️ 取消注释下面这行会 crash(recover 不在 defer 中无效)
|
||
//noRecover()
|
||
}
|