0Pricing
Go Academy · 课时

实用反射:序列化器

使用 reflect 构建简单的类 JSON 序列化器

实用反射:序列化器 是 CoddyKit 上的免费 Go Academy 课时。 这是第 4 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Go Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Go Academy 课程共包含 4 节课。

自定义 JSON 序列化器概览

使用反射构建自定义序列化器,可以展示反射的实际应用:遍历结构体字段、读取标签、访问值并构建输出——encoding/json 内部也采用了相同的方法。

简单的结构体转映射

使用反射将结构体转换为 map[string]any:

func StructToMap(v any) map[string]any {
    t := reflect.TypeOf(v)
    val := reflect.ValueOf(v)
    result := make(map[string]any, t.NumField())
    for i := 0; i < t.NumField(); i++ {
        f := t.Field(i)
        if !f.IsExported() { continue }
        key := f.Tag.Get("json")
        if key == "" { key = f.Name }
        result[key] = val.Field(i).Interface()
    }
    return result
}

处理指针

读取指针字段的值之前,先对其进行解引用:

fv := val.Field(i)
if fv.Kind() == reflect.Ptr {
    if fv.IsNil() { continue }
    fv = fv.Elem()
}

处理嵌套结构体

递归处理嵌套的结构体字段:

if fv.Kind() == reflect.Struct {
    result[key] = StructToMap(fv.Interface())
    continue
}

支持 omitempty

如果标签包含 "omitempty",请跳过零值字段:

if strings.Contains(tag, "omitempty") && fv.IsZero() { continue }

映射转结构体(反序列化器)

通过将映射键与字段标签匹配,从映射填充结构体:

func MapToStruct(m map[string]any, dest any) {
    t := reflect.TypeOf(dest).Elem()
    v := reflect.ValueOf(dest).Elem()
    for i := 0; i < t.NumField(); i++ {
        key := t.Field(i).Tag.Get("json")
        if val, ok := m[key]; ok {
            v.Field(i).Set(reflect.ValueOf(val))
        }
    }
}

类型强制转换

来自 JSON 的映射值通常会将数字表示为 float64。设置字段时,请将其转换为目标字段类型:

if f.Type.Kind() == reflect.Int && reflect.TypeOf(val).Kind() == reflect.Float64 {
    v.Field(i).SetInt(int64(val.(float64)))
}

缓存字段元数据

将字段到标签的映射缓存到以 reflect.Type 为键的 sync.Map 中,避免每次序列化调用都重复进行反射。

代码生成替代方案

对于性能关键路径,请使用 easyjson 或 ffjson 等工具生成特定类型的序列化器。它们完全避免了运行时反射。

何时构建自定义序列化器

以下情况适合使用自定义序列化器:非 JSON 格式(BSON、Avro、CSV)、自定义编码规则或严格的性能要求。对于大多数用例,encoding/json 已经足够。

测试序列化器

往返测试:将结构体序列化为映射,再反序列化回来,并断言值与原始值匹配:

u := User{Name: "Alice", Age: 30}
m := StructToMap(u)
var u2 User
MapToStruct(m, &u2)
assert.Equal(t, u, u2)

快速检查

构建基于反射的序列化器时,为什么字段元数据缓存很重要?

回顾:基于反射的序列化器

要点:

  • 使用 NumField/Field 遍历字段;使用 Tag.Get 读取标签
  • 处理指针、嵌套结构体和零值
  • 为提升性能,在 sync.Map 中缓存字段元数据
  • 使用代码生成可获得最高吞吐量

常见问题解答

「实用反射:序列化器」课时是免费的吗?

是的 — 「实用反射:序列化器」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Go Academy 课程的其余内容,请升级到 CoddyKit PRO。 Go Academy 课程共包含 4 节课。

「实用反射:序列化器」这节课中我会学到什么?

使用 reflect 构建简单的类 JSON 序列化器 你通过在浏览器中直接运行的动手代码来练习 Go Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 Go Academy 需要有经验吗?

无需任何先前经验。CoddyKit 上的 Go Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 4 节课,共 4 节。

「实用反射:序列化器」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 Go Academy 课中编写并运行代码吗?

能。每节 Go Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. reflect.Type 与 reflect.Value
  2. 检查结构体字段与标签
  3. 动态函数调用
  4. 实用反射:序列化器
← 返回 Go Academy