Go 语言圣经 #7_2 | error 接口、类型断言、类型分支、接口设计准则
7.8 error 错误接口1. error 本质标准库预定义接口error是 Go 内置通用错误接口仅定义一个Error()方法gotype error interface { Error() string }任何类型只要实现Error() string方法就自动满足 error 接口可作为错误返回值。2. 快速创建错误errors.New ()导入包import errors底层原理errors.New(xxx)内部返回*errorString结构体指针底层用指针而非结构体值防止外部随意修改错误信息每次调用 New 都会生成全新独立错误实例错误之间不相等使用示例goerr : errors.New(参数不能为空) fmt.Println(err.Error()) // 调用方法输出错误文本3. 设计优势统一所有函数错误返回规范所有异常信息都可通过Error()获取字符串描述。7.9 示例表达式求值本章配套实战案例基于接口实现不同算术表达式统一求值逻辑核心作用演示如何用接口抽象不同运算行为结合 error 接口处理表达式语法、计算异常体现接口抽象解耦不同运算类型的代码设计思想7.10 类型断言 x.(T)1. 基础定义语法接口变量.(类型T)称为类型断言作用检测接口值内部的动态类型是否匹配目标类型 T分两种场景。场景 1T 为具体类型逻辑校验接口动态类型是否等于 T成功提取接口内的动态值类型转为 T失败直接触发 panic 崩溃govar w io.Writer os.Stdout f : w.(*os.File) // 断言成功拿到*os.File场景 2T 为接口类型逻辑校验接口动态类型是否实现 T 接口成功生成新接口值底层动态类型、动态值不变仅对外暴露 T 接口的方法集失败panicgovar r io.Reader os.Stdin rw : r.(io.ReadWriter) // 若底层类型同时实现读写接口则成功2. 安全断言双返回值推荐单返回值断言失败会 panic工程中使用value, ok : x.(T)安全写法oktrue类型匹配value 为对应值okfalse类型不匹配value 为 T 类型零值不会崩溃gof, ok : w.(*os.File) if ok { // 执行文件专属逻辑 }3. 特殊规则若接口值本身是 nil动态类型、动态值全 nil任何类型断言都失败可复用原变量接收断言结果覆盖原有变量值7.11 基于类型断言区分细分错误1. 基础错误判断函数os 包文件操作提供快速判断错误类型工具函数底层基于类型断言实现gofunc IsExist(err error) bool // 文件已存在 func IsNotExist(err error) bool // 文件不存在 func IsPermission(err error) bool // 权限不足缺陷不同操作系统底层错误描述不一致仅简单字符串判断不够健壮。2. 结构化错误类型可靠方案标准库定义专用结构体存储完整错误上下文比单纯字符串判断更精准os.PathError单文件路径操作失败Open/Delete字段操作名称、文件路径、底层原始错误os.LinkError双路径操作失败Symlink/Rename3. 正确区分错误流程业务通用场景直接调用err.Error()打印统一错误文本需要细分处理异常使用类型断言提取底层结构化错误goif pe, ok : err.(*os.PathError); ok { fmt.Println(操作, pe.Op, 路径, pe.Path) }优势直接读取结构化字段不受系统错误文本差异影响。7.12 类型分支 switch x.(type)1. 接口两种使用场景场景 A行为抽象主流代表类型io.Reader、error、sort.Interface、http.Handler核心接口定义统一行为方法隐藏底层具体类型关注行为而非类型。场景 B可辨识联合Discriminated Unions接口仅作为多种类型的容器依靠类型断言 / 分支区分底层类型不隐藏细节关注具体类型。典型场景SQL 参数解析、多类型参数统一接收。2. 类型分支语法特殊 switchswitch 变量.(type)仅能在 switch 中使用type关键字goswitch v : data.(type) { case int: // v是int类型 case string: // v是string类型 case nil: // 接口值为nil default: // 其他所有类型 }自动提取对应类型值到分支内变量 vnil 分支匹配空接口值default 匹配所有未命中类型3. Go 接口设计最佳实践核心面试考点不要提前定义仅单个实现的接口单一实现的接口属于多余抽象带来额外运行时开销直接导出类型方法即可。接口使用的正确时机至少两种具体类型需要统一处理唯一例外包解耦场景实现类型与接口分属不同包无法直接依赖用接口消除包依赖。小接口优先设计原则只定义需要的方法ask only for what you need如io.Writer仅 1 个 Write 方法小接口更容易被新类型实现扩展性更强。配套案例SQL 参数解析SQL 语句中?占位符需要接收布尔、数字、字符串、nil 多类型参数使用类型分支区分不同参数类型转换为标准 SQL 字面量同时规避 SQL 注入风险。本章总结error是内置单方法接口errors.New()快速生成错误底层为指针结构体类型断言x.(T)分具体类型 / 接口类型两种匹配逻辑单返回值失败 panic双返回值安全判断区分 IO 错误优先使用结构化PathError 类型断言不依赖错误字符串判断类型分支switch x.(type)专门用于接口多类型分发实现可辨识联合接口两大用途行为抽象、多类型容器接口设计准则多实现再抽象优先小接口不造单实现冗余接口