函数里明确写了 `return err`,调用方拿到的 err 却是 nil,日志里明明打印过错误内容,接口照常返回 200,翻了半天也没找到哪里把错误重新赋成了空值。乍看像缓存或者权限的锅,追下去往往不是。
grep -n 'defer func' -r . grep -n 'func.*(.*err error)' -r . go vet ./...
追下去是这么回事:函数用了命名返回值,defer 里对 err 重新赋值,defer 在 return 赋值之后执行,会把已经算好的返回值覆盖掉,看起来就像错误被吞了,位置还特别难找。
「defer 改返回值」这个问题文档写得含糊,实际行为以当前版本为准,别照旧版本的结论套。验证用真实数据走一遍,测试数据太干净,边界情况根本碰不到。
能分两步做的操作就别合成一步,中间看一眼返回值,出问题好判断。
具体做法是,先检查函数签名里的返回值是不是命名返回值;确认延迟调用里面有没有改动过那个返回变量;要记日志就单独存一个变量,不要覆盖错误值。
验收就看一点,构造一个失败用例,接口返回 500,且拿到的错误与日志内容完全一致。
