Go语言json包为何刻意不编组未导出结构体字段?
Go JSON编解码中未导出字段的限制与问题解决
在Go的encoding/json包中,若要让结构体字段通过tag参与JSON编组(Marshal)和解组(Unmarshal),字段必须是导出的。不少开发者误以为这是reflect包的限制,但实际上是JSON编码包主动拒绝处理未导出字段。
这种限制会带来两个常见的实践痛点:
- 为了支持JSON编解码不得不导出过多字段,导致外部代码可以直接修改这些字段的值,绕开了原本设计的getter/setter方法,破坏了结构体的封装性
- 若要维持封装性,专门创建一个仅用于JSON编解码的同名结构体(仅调整字段导出性),又会产生大量重复冗余代码
以下是一个可以读取未导出字段tag的实现示例:
package main import ( "reflect" "unsafe" ) type MyStruct struct { field string `json:"my_field"` } func getUnexportedFieldTag(obj interface{}, fieldName string) string { val := reflect.ValueOf(obj) if val.Kind() == reflect.Ptr { val = val.Elem() } // 获取未导出字段的反射值 field := val.FieldByName(fieldName) // 通过unsafe包绕过访问限制,获取字段的元信息 fieldPtr := unsafe.Pointer(field.UnsafeAddr()) reflectField := reflect.NewAt(field.Type(), fieldPtr).Elem() return reflectField.Type().Field(0).Tag.Get("json") } func main() { s := MyStruct{field: "demo"} println(getUnexportedFieldTag(&s, "field")) // 输出: my_field }
编辑补充:感谢@mkopriva提供更简洁高效的实现方案。
内容的提问来源于stack exchange,提问作者Stephen
相关产品推荐
相关产品推荐

