
go语言的json.unmarshal函数只能对导出(即首字母大写的)结构体字段进行反序列化,小写字母开头的字段因不可导出而被忽略,始终保持零值。
go语言的json.unmarshal函数只能对导出(即首字母大写的)结构体字段进行反序列化,小写字母开头的字段因不可导出而被忽略,始终保持零值。
在Go中,结构体字段的可见性(exported/unexported) 由其名称首字母决定:首字母为大写(如 Name, Score)表示该字段是导出的(exported),可在包外访问;首字母为小写(如 name, score)则为未导出的(unexported),仅限当前包内使用。
encoding/json 包在执行 json.Unmarshal 时,严格遵循 Go 的反射规则——它仅能读取和设置导出字段。这是因为 json 包无法通过反射修改未导出字段(即使同包内也不行),这是 Go 语言安全模型的设计约束,而非实现缺陷。
以下示例清晰展示了这一行为:
将一个或多个视频上传至YouTube。当用户想“上传到YouTube”“发YouTube”“批量上传”“upload to YouTube”“post videos to YouTube”或发布到YouTube时使用此技能。
package main
import (
"encoding/json"
"fmt"
)
type GameOne struct {
Name string `json:"name"`
Score int `json:"score"`
}
type GameTwo struct {
name string `json:"name"` // ❌ 未导出,反序列化时被跳过
score int `json:"score"` // ❌ 同样被跳过
}
func main() {
data := []byte(`{"name":"Chess","score":100}`)
var g1 GameOne
json.Unmarshal(data, &g1)
fmt.Printf("GameOne: %+v\n", g1) // 输出:{Name:"Chess" Score:100}
var g2 GameTwo
json.Unmarshal(data, &g2)
fmt.Printf("GameTwo: %+v\n", g2) // 输出:{name:"" score:0} —— 字段保持零值
}
⚠️ 注意事项:
- 即使添加了
json标签(如json:"name"),也无法使未导出字段参与序列化/反序列化; - 若需隐藏字段但又支持 JSON 解析,可改用嵌入导出字段 + 自定义 MarshalJSON/UnmarshalJSON 方法,或使用中间结构体转换;
- 所有标准编码包(如
xml,yaml)均遵循相同导出规则。
总结:这不是 bug,而是 Go 明确的设计哲学——“封装通过命名控制,反射仅作用于导出标识符”。因此,在设计需 JSON 交互的结构体时,务必确保关键字段首字母大写,并合理使用结构体标签(如 json:"field_name,omitempty")控制序列化行为。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










