Go语言修改value或struct的常见方式及行业最佳实践选择
在Go语言生态中,这两种实现没有绝对的高低之分,优先选哪种完全取决于你的业务场景,不过绝大多数通用业务开发场景下,更推荐你用第二种「返回值+错误处理后赋值」的方案,原因如下:
- 符合Go语言显式错误处理的设计哲学:第二种方案强制调用方处理错误,不可能出现异常被吞的情况。反观你示例中的第一种
handleResponse实现,当AdType为非法值时,只会给Response的Message赋空值,调用方完全无法区分这是正常业务返回的空值还是执行出错导致的空值,排查问题会非常麻烦。 - 逻辑无副作用,可测性更高:第二种
getRequestMessage是无状态的纯逻辑,输入只依赖Request的属性,输出只有结果和错误,写单元测试的时候只要断言返回值是否符合预期即可。而第一种方案依赖外部传入的指针变量,会直接修改外部变量的状态,调试、单测的复杂度都会更高。 - 可读性更强:调用第二种方法的代码一眼就能看出来是要给res2.Message赋值,逻辑链路清晰。调用第一种方法的时候,你必须点进
handleResponse的实现才能知道它会修改传入的res参数,代码可读性差很多。
当然第一种「按引用传递参数修改」的方案也有适用场景:
- 待修改的结构体体积很大:如果你的Response结构体内存占用达到几十KB甚至更高,返回完整结构体拷贝会产生明显的性能损耗,这时候传指针修改可以避免不必要的内存拷贝。
- 需要同时修改多个外部变量:如果一个方法要同时更新多个关联对象的属性,传指针修改比返回N个值再逐个赋值的可读性更高。
- 构造器/链式调用场景:很多Go的第三方库(比如ORM、配置解析库)都会用指针接收者修改自身属性,支持
config.WithA().WithB().Build()这类链式调用,这种场景下传指针修改的方案更合适。
如果确实要选择传指针修改的方案,建议你给方法加上错误返回,不要吞掉异常,示例如下:
func (req *Request) handleResponse(res *Response) error { if req.AdType == "banner" { res.Message = "Banner Ad" return nil } else if req.AdType == "video"{ res.Message = "Video Ad" return nil } return errors.New("Invalid ad type") }
调用的时候也需要显式判断错误,避免隐藏异常。
内容的提问来源于stack exchange,提问作者Samiul Amin Shanto
相关产品推荐
相关产品推荐

