🐸 青蛙编程网
首页 / Go / Go 基础 / 6. 接口与错误处理

6. 接口与错误处理

这是什么:接口(interface) = 只列方法名的能力契约;error = Go 内置的错误类型,所有失败都用返回值表示。

为什么用:上一章的 struct 靠字段名硬绑,想让不同类型干同一件事只能挨个判断类型;出错用 panic 兜底,容易整段崩掉。接口让代码只认「会不会某件事」,error 让失败沿直线传回调用方。

如何用:先定义只列 Speak() 的 Speaker 接口,让 Dog 和 Robot 各自实现,再写一个返回 error 的函数,用 if err != nil 接住失败。

6.1 接口:一纸能力契约

type Speaker interface {
    Speak() string      // 只要你有 Speak() 你就是 Speaker
}

隐式实现(不用声明 implements):

type Dog struct{}
func (d Dog) Speak() string { return "汪" }

type Robot struct{}
func (r Robot) Speak() string { return "哔" }

// 都满足 Speaker,可统一处理
func makeSound(s Speaker) {
    fmt.Println(s.Speak())
}
makeSound(Dog{})     // 汪
makeSound(Robot{})   // 哔

隐式接口 = 「长得像,就当是」。标准库 io.Writer、fmt.Stringer 全靠这招贯穿生态。

6.2 error 是接口不是异常

Go 没有 try/catch——所有可失败操作返回 error,代码像直线:

f, err := os.Open("missing.txt")
if err != nil {
    fmt.Println("打开失败:", err)
    return             // 或返回 err 一路上抛
}
defer f.Close()        // 成功才注册收尾

造一个错误:

errors.New("意外输入")
fmt.Errorf("值 %d 不合法", n)     // 带格式 + 可包内层错误 %w(进阶)

自定义错误类型(承载更多信息):

type NotFound struct{ Key string }
func (e NotFound) Error() string { return "找不到:" + e.Key }

金句:错误是值。看得见流向、写起测试简单,也是 Go 代码「if err != nil」铺地面的原因。

6.3 panic 与 recover(慎用)

  • panic:程序不可继续的致命错误(如数组彻底越界)
  • recover:在 defer 中捞回 panic,一般只在最外层兜底(Web 框架替你做了)
defer func() {
    if r := recover(); r != nil {
        fmt.Println("救回:", r)
    }
}()

规矩:业务错误用 error,系统崩溃才 panic。

6.4 判断与断言

var s Speaker = Dog{}
d, ok := s.(Dog)          // 类型断言:s 是 Dog 吗
if ok { fmt.Println(d.Breed) }

// switch 版
switch v := s.(type) {
case Dog:  fmt.Println("狗", v)
case Robot: fmt.Println("机器人")
}

6.5 动手改

  1. 写 Animal 泛型 Speaker 实现(Cat、Robot),slot makeSound
  2. divide 函数换成自定义错误「除数不能为 0」,调用方别忘了检查
  3. 手造 panic 并 recover 观察

6.6 小结

  • 接口 = 方法签名清单,隐式实现一词两环境
  • 一切错误是值:(res, err) + 检查和向上传递
  • panic 保命、recover 清理,平时同 error

下一章:并发:goroutine 与 channel 🐸

📥 下载本章代码

ZIP 内含本章全部代码文件与说明,解压即用,与教程内容同步生成。