
本文详解 go 语言中使用 encoding/json 解析 json 时结构体字段标签(Struct tags)的规范写法,重点纠正常见错误——遗漏 json 标签中的双引号,导致反序列化失败并返回零值。
在 go 中,将 json 字符串解码为 Go 结构体是高频操作,但一个看似微小的语法细节却常引发“解析成功但字段为空”的隐蔽问题:JSON struct tag 中的键名必须用英文双引号包裹。若误写为反引号内无引号(如 `json:access_token`),Go 会忽略该标签,转而按字段名(首字母大写的导出名)匹配 JSON 键,而 JSON 中的键是小写的 access_token,无法匹配,最终所有字段保持零值。
以下是一个典型错误示例及其修复:
package main import ( "encoding/json" "fmt" ) // ❌ 错误写法:struct tag 中缺少双引号 type ApiParams struct { AccessToken string `json:access_token` // 编译通过,但运行时被忽略! TokenType string `json:token_type` ExpiresIn int64 `json:expires_in` } func main() { data := `{ "access_token": "asdfasdf", "token_type": "bearer", "expires_in": 5173885 }` var apiParams ApiParams err := json.Unmarshal([]byte(data), &apiParams) if err != nil { fmt.Println("解码错误:", err) return } fmt.Printf("%+vn", apiParams) // 输出:{AccessToken:"" TokenType:"" ExpiresIn:0} }
运行结果为空结构体,正是因为 json:access_token 是非法 tag(缺少双引号),Go 默认使用字段名 AccessToken 去匹配 JSON 中的 “access_token”,显然不匹配。
✅ 正确写法如下——每个 JSON key 必须用双引号包裹在 struct tag 内:
type ApiParams struct { AccessToken string `json:"access_token"` // ✅ 正确:双引号包裹 key TokenType string `json:"token_type"` ExpiresIn int64 `json:"expires_in"` }
完整可运行示例:
package main import ( "encoding/json" "fmt" ) type ApiParams struct { AccessToken string `json:"access_token"` TokenType string `json:"token_type"` ExpiresIn int64 `json:"expires_in"` } func main() { data := `{ "access_token": "asdfasdf", "token_type": "bearer", "expires_in": 5173885 }` var apiParams ApiParams if err := json.Unmarshal([]byte(data), &apiParams); err != nil { panic(err) } fmt.Printf("Token: %sn", apiParams.AccessToken) // 输出:Token: asdfasdf fmt.Printf("Type: %sn", apiParams.TokenType) // 输出:Type: bearer fmt.Printf("Expires in: %d secondsn", apiParams.ExpiresIn) // 输出:Expires in: 5173885 seconds }
? 关键注意事项:
- Struct tag 语法为 `key:”value”`,其中 json 是 key,”access_token” 是 value,双引号不可省略;
- 若 JSON 键与 Go 字段名完全一致(且大小写匹配),可省略 tag(如字段名 AccessToken 对应 JSON “AccessToken”),但实践中绝大多数 API 返回小写下划线命名(snake_case),必须显式指定;
- 支持额外选项,例如忽略空值:json:”expires_in,omitempty”,或指定字段为必需(需配合自定义解码逻辑);
- 使用 json.RawMessage 可延迟解析嵌套 JSON,提升灵活性;
- 始终检查 json.Unmarshal 的返回 Error,避免静默失败。
掌握这一基础但关键的语法规范,能显著减少 JSON 解析类 bug,提升 Go 服务对接外部 API 的健壮性与开发效率。