Go 是静态类型语言,这意味着你需要显式的结构体定义来处理 JSON 数据。与 JavaScript 或 Python 不同,你不能将 JSON 解析成动态 map 然后自由访问属性。理解如何将 JSON 映射到 Go 结构体对于构建健壮的 Go 应用至关重要。
使用我们的免费工具即时将 JSON 转换为 Go 结构体 →
为什么 Go 需要结构体定义
Go 的 encoding/json 包使用结构体标签和反射来序列化和反序列化 JSON。没有正确的结构体定义,你只能使用 map[string]interface{},这会失去类型安全并需要运行时类型断言。
- 类型安全——编译器在构建时捕获类型不匹配
- 性能——结构体访问比 map 查找快得多
- 自动补全——编辑器知道可用的字段及其类型
- 文档化——结构体定义可作为自文档化的 API 契约
类型映射
JSON 类型与 Go 类型的映射如下:
| JSON 类型 | Go 类型 | 备注 |
|---|---|---|
| string | string | UTF-8 编码 |
| number (整数) | int / int64 | 大值使用 int64 |
| number (浮点数) | float64 | JSON 数字的默认类型 |
| boolean | bool | |
| null | *T (指针) | null 时为 nil |
| array | []T | 类型化元素的切片 |
| object | struct | 命名结构体类型 |
JSON 结构体标签
Go 使用结构体字段标签来控制 JSON 键如何映射到结构体字段。json 标签至关重要:
// JSON
{
"user_name": "alice",
"email_address": "alice@example.com",
"is_active": true,
"login_count": 42
}
// Go struct
type User struct {
UserName string `json:"user_name"`
EmailAddress string `json:"email_address"`
IsActive bool `json:"is_active"`
LoginCount int `json:"login_count"`
}Go 中的字段名必须导出(首字母大写)才能被 JSON 包识别。结构体标签将导出的 Go 名称映射到小写的 JSON 键。
omitempty 选项
omitempty 标签选项告诉 JSON 编码器在序列化时跳过零值字段。这对构建灵活的 API 请求体至关重要:
type UpdateRequest struct {
Name string `json:"name,omitempty"`
Email string `json:"email,omitempty"`
Age *int `json:"age,omitempty"` // pointer: distinguish 0 from absent
Bio *string `json:"bio,omitempty"` // pointer: distinguish "" from absent
}
// Only "name" appears in the output:
req := UpdateRequest{Name: "Alice"}
data, _ := json.Marshal(req)
// {"name":"Alice"}各类型的零值:字符串为 "",数字为 0,布尔为 false,指针/切片/映射为 nil。当需要区分"未设置"和"零值"时,使用指针(*int、*string)。
嵌套结构体
包含嵌套对象的复杂 JSON 需要为每个层级定义单独的结构体类型:
// JSON
{
"id": 1,
"name": "Alice",
"company": {
"name": "Acme Corp",
"address": {
"city": "Springfield",
"country": "US"
}
},
"skills": ["go", "rust", "python"]
}
// Go structs
type Address struct {
City string `json:"city"`
Country string `json:"country"`
}
type Company struct {
Name string `json:"name"`
Address Address `json:"address"`
}
type User struct {
ID int `json:"id"`
Name string `json:"name"`
Company Company `json:"company"`
Skills []string `json:"skills"`
}提示:对于深度嵌套的 JSON,分别定义每个结构体。避免对可复用的子对象使用匿名结构体。仅对一次性、不可复用的结构使用内联匿名结构体。
常见模式
以下是在 Go 中处理 JSON 时经常遇到的模式:
// Pattern 1: API response wrapper
type APIResponse[T any] struct {
Data T `json:"data"`
Message string `json:"message"`
Status int `json:"status"`
}
// Pattern 2: Flexible field with json.RawMessage
type Event struct {
Type string `json:"type"`
Payload json.RawMessage `json:"payload"` // decode later based on Type
}
// Pattern 3: Custom JSON key with "-" to ignore
type Internal struct {
PublicID string `json:"id"`
SecretKey string `json:"-"` // never marshaled/unmarshaled
}
// Pattern 4: Unmarshal usage
var user User
err := json.Unmarshal([]byte(jsonString), &user)
if err != nil {
log.Fatal(err)
}
fmt.Println(user.Name) // "Alice"自动化转换
从大型 JSON 负载手动编写 Go 结构体非常繁琐。我们的 JSON to Go 转换器可以从任何 JSON 输入自动生成带有正确标签的结构体定义——包括嵌套对象、数组和可选字段。