Golang如何正确判断处理context.deadlineExceededError错误
问题
尝试在异常处理的type switch中按类型匹配Golang的context deadline exceeded错误,编写代码如下:
switch err.(type) case context.deadlineExceededError: fmt.Println("deadline exceeded") }
代码无法编译,报错信息:
cannot refer to unexported name context.deadlineExceededError
由于context.deadlineExceededError是context包的未导出类型,包外代码无法直接引用,有开发者尝试通过字符串比较类型名的方式处理:
case <-ctx.Done(): err := ctx.Err() errType := fmt.Sprintf("%T",err) switch errType { case "context.deadlineExceededError": fmt.Println("deadline") } fmt.Printf("error %T: %v\n", err, err) }
该方式虽然可正常运行,但不符合Golang错误处理规范,需要更标准的判断方案。
原因
deadlineExceededError是context包定义的私有未导出类型,按照Go的访问控制规则,包外代码无权直接引用该类型,因此直接在type switch中匹配该类型会触发编译错误。
通过字符串比对类型名的方式没有兼容性保障,一旦Go标准库调整内部错误的实现逻辑、修改类型命名,相关判断逻辑会直接失效,属于不推荐的非标准用法。
标准解决方案
Go标准库已经为该场景提供了官方支持的判断方式,不需要做类型匹配或者字符串比较:
- context包导出了两个公开的哨兵错误:
context.DeadlineExceeded代表上下文截止时间超时,context.Canceled代表上下文被主动取消 - Go 1.13版本引入错误包装机制后,使用标准库
errors.Is()方法即可判断错误链中是否包含目标错误,兼容所有经过包装的context错误,是官方推荐的标准写法。
正确的实现代码:
package main import ( "context" "errors" "fmt" "time" ) const shortDuration = 1 * time.Second func main() { ctx, cancel := context.WithTimeout(context.Background(), shortDuration) defer cancel() select { case <-time.After(shortDuration*2): fmt.Println("overslept") case <-ctx.Done(): err := ctx.Err() switch { case errors.Is(err, context.DeadlineExceeded): fmt.Println("deadline exceeded") case errors.Is(err, context.Canceled): fmt.Println("context canceled") default: fmt.Printf("unknown error: %v\n", err) } fmt.Printf("error %T: %v\n", err, err) } }
编译运行输出:
deadline exceeded error context.deadlineExceededError: context deadline exceeded
补充:如果使用Go 1.13以前的旧版本,可以直接通过
err == context.DeadlineExceeded做相等判断,但该方式无法识别被包装过的错误,优先推荐使用errors.Is实现判断逻辑。
内容的提问来源于stack exchange,提问作者Craig Ringer
相关产品推荐
相关产品推荐

