拿到一段 JSON,需要写 Go struct 来反序列化。手写意味着要逐个确定字段类型、添加 json:"..." 标签、处理嵌套对象——机械且容易出错。把 JSON 粘贴进去,几秒出结构体定义。

手写 Go Struct 的麻烦

Go 要求明确定义带标签的结构体字段:

  • 每个字段需要写对类型:stringintfloat64bool[]T、嵌套结构体
  • 字段名不匹配时需要 json:"..." 标签
  • JSON snake_case 键对应 Go CamelCase 字段,每个都要手动加标签
  • 可选字段需要指针类型(*string)或 omitempty
  • 嵌套对象需要分别定义多个结构体
  • 规模稍大就容易出错

一个 5 个字段的对象还好。10 个嵌套对象加数组,手写就是实实在在的负担。

生成器的工作原理

生成器读取 JSON,自动生成带正确类型和 json 标签的 Go struct。以这段 JSON 为例:

{
  "user": {
    "id": 42,
    "name": "张三",
    "email": "[email protected]",
    "is_active": true,
    "roles": ["admin", "editor"],
    "address": {
      "city": "上海",
      "country": "CN",
      "zip_code": "200000"
    },
    "last_login": null
  }
}

生成结果:

type Address struct {
    City    string `json:"city"`
    Country string `json:"country"`
    ZipCode string `json:"zip_code"`
}

type User struct {
    ID        int      `json:"id"`
    Name      string   `json:"name"`
    Email     string   `json:"email"`
    IsActive  bool     `json:"is_active"`
    Roles     []string `json:"roles"`
    Address   Address  `json:"address"`
    LastLogin *string  `json:"last_login"`
}

type Root struct {
    User User `json:"user"`
}

使用 ZeroTool JSON 转 Go Struct 生成器 →

粘贴 JSON,立即得到 Go struct。所有计算在浏览器本地完成,数据不离开你的机器。

类型推断规则

JSON 值Go 类型
"字符串"string
42int
3.14float64
true / falsebool
null*T(指针,可为 nil)
[1, 2, 3][]int
[{…}, {…}][]StructName
{}命名结构体

null 值处理

Go 中 null 自然映射到指针类型。JSON 中的 null 值变为 *string*int 等——JSON 为 null 时指针为 nil

LastLogin *string `json:"last_login"` // JSON 为 null 时值为 nil

如果 API 保证字段永不为 null,可以在审查文档后改为值类型。

snake_case 到 CamelCase

Go 导出字段使用 CamelCase。生成器自动转换 JSON snake_case 键并添加对应的 json 标签:

// JSON 键:zip_code
ZipCode string `json:"zip_code"`

没有标签,encoding/json 会在 JSON 中查找 ZipCode 而不是 zip_code

常见边界情况

数字类型精度

JSON 只有一种数字类型。生成器推断规则:

  • 无小数点 → int
  • 有小数点 → float64

对于超过 32 位整数范围的大 ID(如雪花算法 ID),需要改为 int64

// 生成结果
ID int `json:"id"`

// 超大 ID
ID int64 `json:"id"`

空数组

[] 没有元素类型信息,生成器输出 []interface{}。查阅 API 文档后替换为正确的元素类型。

可选字段

字段在 JSON 中可能不存在(而不是为 null)时,手动加 omitempty

Email string `json:"email,omitempty"`

生成器为 null 值字段生成指针类型,但不会自动加 omitempty,需要手动补充。

使用生成的结构体

反序列化

import "encoding/json"

var root Root
if err := json.Unmarshal([]byte(jsonString), &root); err != nil {
    log.Fatal(err)
}
fmt.Println(root.User.Name)

配合 net/http

resp, err := http.Get("https://api.example.com/users/1")
if err != nil {
    log.Fatal(err)
}
defer resp.Body.Close()

var root Root
if err := json.NewDecoder(resp.Body).Decode(&root); err != nil {
    log.Fatal(err)
}

序列化

output, err := json.MarshalIndent(root.User, "", "  ")
if err != nil {
    log.Fatal(err)
}
fmt.Println(string(output))

配合主流框架

Gin、Echo、Fiber 等框架可以直接使用同一套结构体:

// Gin
func GetUser(c *gin.Context) {
    var user User
    if err := c.ShouldBindJSON(&user); err != nil {
        c.JSON(400, gin.H{"error": err.Error()})
        return
    }
    c.JSON(200, user)
}

扩展标签

生成器默认只添加 json 标签。根据技术栈,可能还需要:

// GORM 数据库映射
type User struct {
    ID   int    `json:"id" gorm:"primaryKey"`
    Name string `json:"name" gorm:"column:name"`
}

// go-playground/validator 校验
type User struct {
    Email string `json:"email" validate:"required,email"`
}

// MongoDB BSON
type User struct {
    ID   primitive.ObjectID `json:"id" bson:"_id,omitempty"`
    Name string             `json:"name" bson:"name"`
}

在生成基础结构体后手动添加这些标签。

小结

JSON 转 Go Struct 生成器省去了机械性的类型推断和标签编写工作。生成后的检查清单:

  • 超大数字 ID 改为 int64
  • 可选字段加 omitempty
  • []interface{} 替换为正确的元素类型
  • 按需添加 validate、gorm、bson 等标签
  • API 保证非 null 的字段改为值类型(去掉指针 *

在线生成 Go Struct,数据不离开浏览器 →