💜 想真正擅长编程? 从一门课程开始,100% 免费

《笔记》第二十篇 模拟Error

第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 { ... } 模式

九、课后练习

  1. 定义一个 User 结构体(Name, Age),编写函数验证Age是否合法(1-150),不合法返回error
  2. 编写一个函数 parseInt(s string) (int, error),模拟Go的 strconv.Atoi 函数
  3. 调用上面的函数,分别处理正常和错误情况
  4. 尝试用 _ 忽略error,思考这样做的风险
  5. 编写一个匿名函数,实现两个数相乘的功能
  6. 编写一个可变参数函数 max(nums ...int) int,返回最大值