go中if err != nil后必须return等终止动作,否则后续代码在无效状态运行易panic;defer需紧随资源获取且变量已初始化;错误统一返回error接口,用%w包装保留链;http handler尽早返回不影响连接关闭。

Go 里 if err != nil 后不加 return 就继续往下跑?
这是最常踩的坑:错误分支没中断执行,后续代码在无效状态里硬跑,要么 panic,要么返回错得离谱的结果。
比如调用 os.Open 失败后没 return,还去对一个 nil 的 *os.File 调用 Read,直接 panic。
- 所有非空
err分支,只要逻辑不能继续,就必须跟return(或panic、os.Exit等终止动作) - 别用
else包裹正常流程——“尽早返回”不是“必须 else”,而是让成功路径保持左对齐、无缩进 - 如果错误要透传,用
return err,别只写return(除非函数签名是func() error)
多个 I/O 操作串联时,defer file.Close() 放哪儿?
放在打开之后立刻 defer,而不是等所有操作做完再 defer。否则一旦中间出错,file 可能是 nil,defer file.Close() 会 panic。
典型反例:file, err := os.Open(...); if err != nil { return err }; defer file.Close(); ... // 中间某步出错,file 已 close,但后续又 try to use it
立即学习“go语言免费学习笔记(深入)”;
-
defer要紧挨着资源获取语句,且确保该变量已有效初始化 - 如果函数里开了多个文件,每个都独立 defer;别想着“统一在结尾 close”,那会漏关或 panic
- 注意
defer在return前执行,但它的参数在 defer 语句执行时就求值了——所以defer fmt.Println(x)打印的是 defer 时的x,不是 return 时的
函数返回多个 error(比如 error 和自定义错误类型)怎么处理?
Go 标准做法是只返回一个 error 接口,自定义错误类型实现 Error() string 方法即可。混用多个 error 类型反而破坏一致性,增加判断负担。
常见误操作:函数签名写成 func() (int, error, *MyErr),调用方还得三元判断。
- 所有错误统一走
error返回值,用errors.Is或errors.As做运行时识别 - 需要携带上下文?用
fmt.Errorf("xxx: %w", err)包装,保留原始 error 链 - 别在错误处理里做日志打印(如
log.Printf)——那是上层调用者的职责;底层函数只负责返回可识别的 error
HTTP handler 里用“尽早返回”会不会导致连接没关干净?
不会。只要 handler 函数返回,net/http 服务端就会结束响应、关闭连接(除非用了流式响应如 http.Flusher)。但要注意:手动写的 defer responseWriter.WriteHeader 这类操作没意义,因为 WriteHeader 只能调一次,且一旦写了 header,body 写入就不可逆。
- handler 内部出错,直接
return即可;别为了“清理”而多写逻辑 - 需要统一错误响应格式?封装一个
writeError(w http.ResponseWriter, status int, err error)函数,里面调w.WriteHeader+w.Write,然后return - 别在 handler 里启动 goroutine 后就
return——那可能还在读 body,而 connection 已断,导致io.ErrUnexpectedEOF
真正容易被忽略的是:错误包装时用 %w 还是 %v,差一个字符,整个错误链就断了。还有 defer 的执行时机和参数绑定,看着简单,一动就错。










