Go中复制指针内容是否会产生不必要开销?以UnmarshalJSON实现为例
Go 自定义UnmarshalJSON写法疑问解答
核心错误:直接修改指针参数对外部无效
Go语言所有函数参数(包括方法接收器)都是值拷贝,这里的接收器s *State本质是外部调用方传入的State指针的本地副本。你提出的s = (*State)(&state)写法,只是修改了当前函数栈内的本地指针变量的指向,外部调用方持有的原State指针、以及原指针指向的内存内容完全不会发生任何变化,JSON解析结果根本无法传递到方法外部,属于逻辑层面的错误,和效率没有任何关系。
原写法的正确性说明
原代码中*s = *(*State)(&state)的逻辑是完全符合要求的:
- 首先
type rawState State是Go自定义JSON解析的常用技巧:因为State已经实现了UnmarshalJSON方法,如果直接用State类型接收解析,json库会递归调用自定义方法导致栈溢出。而rawState是全新类型,没有自定义UnmarshalJSON实现,会走默认的反射解析逻辑,完美规避递归问题。 - 因为
rawState是State的类型别名,两者内存布局完全一致,所以(*State)(&state)的类型转换是安全的。 - 最后的
*s = *xxx是解引用指针,把解析到state变量里的全部内容,直接拷贝到外部调用方传入的s指向的内存地址上,符合UnmarshalJSON接口的约定:把解析结果写入调用方提供的实例中。
拷贝开销相关补充
这里的结构体拷贝开销极低:如果State是小结构体,拷贝成本可以忽略;就算State包含大量字段,拷贝的开销也远小于JSON解析本身的开销,完全不需要优化。就算有极致性能需求,也不能通过修改本地指针副本的方式实现,因为外部调用方根本拿不到新分配的实例。
内容的提问来源于stack exchange,提问作者user1836966
相关产品推荐
相关产品推荐

