
本文详解 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("%+v\n", 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: %s\n", apiParams.AccessToken) // 输出:Token: asdfasdf
fmt.Printf("Type: %s\n", apiParams.TokenType) // 输出:Type: bearer
fmt.Printf("Expires in: %d seconds\n", 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 的健壮性与开发效率。










