Go语言reflect包可动态获取变量类型和值,结合JSON库实现通用序列化;2. 通过reflect.ValueOf和TypeOf获取反射对象,利用Kind判断类型,Field遍历结构体字段,结合结构体标签可动态生成JSON。

Go语言的reflect包可以在运行时动态获取变量类型和值,结合JSON标准库,能实现通用的序列化逻辑。虽然实际开发中推荐使用encoding/json自带的结构体标签机制,但在某些需要完全动态处理的场景(如中间件、通用数据转换工具),reflect非常有用。
理解reflect基本操作
要实现通用JSON序列化,先掌握如何通过反射读取字段:
- reflect.ValueOf() 获取值的反射对象
- reflect.TypeOf() 获取类型的反射对象
- 通过
.Kind()判断是否为结构体、map、slice等 - 使用
.Field(i)和.NumField()遍历结构体字段 - 检查字段是否可导出(首字母大写)
例如,一个结构体字段可以通过反射获取其名称和值:
val := reflect.ValueOf(obj).Elem()typ := val.Type()
for i := 0; i field := val.Field(i)
if field.CanInterface() {
name := typ.Field(i).Name
fmt.Println(name, ":", field.Interface())
}
}
处理结构体字段与json标签
JSON序列化需识别json:"fieldName"标签。通过反射可以提取该信息:
立即学习“go语言免费学习笔记(深入)”;
- 使用
typ.Field(i).Tag.Get("json")获取json标签 - 若标签为空或为"-",跳过该字段
- 解析标签中的选项,如
omitempty
示例代码片段:
tag := typ.Field(i).Tag.Get("json")if tag == "-" { continue }
parts := strings.Split(tag, ",")
jsonName := parts[0]
if jsonName == "" {
jsonName = typ.Field(i).Name
}
这样就能确定输出JSON中的键名。
一套面向小企业用户的企业网站程序!功能简单,操作简单。实现了小企业网站的很多实用的功能,如文章新闻模块、图片展示、产品列表以及小型的下载功能,还同时增加了邮件订阅等相应模块。公告,友情链接等这些通用功能本程序也同样都集成了!同时本程序引入了模块功能,只要在系统默认模板上创建模块,可以在任何一个语言环境(或任意风格)的适当位置进行使用!
递归构建JSON数据结构
使用反射需支持嵌套结构,比如结构体包含结构体、slice、指针等:
- 遇到指针时,用
.Elem()解引用 - 遇到slice时,逐个元素递归处理
- 遇到结构体时,遍历字段并收集键值对
- 基础类型(string、int等)直接转为JSON兼容值
最终可以构造一个map[string]interface{}或[]interface{},再用json.Marshal转成字节流。
简化版通用序列化函数示例
以下是一个极简实现思路:
func ToJSON(v interface{}) ([]byte, error) {rv := reflect.ValueOf(v)
return json.Marshal(toMap(rv))
}
func toMap(v reflect.Value) interface{} {
switch v.Kind() {
case reflect.Ptr:
if v.IsNil() { return nil }
return toMap(v.Elem())
case reflect.Struct:
m := make(map[string]interface{})
typ := v.Type()
for i := 0; i fv := v.Field(i)
if !fv.CanInterface() { continue }
tag := typ.Field(i).Tag.Get("json")
if tag == "-" { continue }
name := strings.Split(tag, ",")[0]
if name == "" {
name = typ.Field(i).Name
}
m[name] = toMap(fv)
}
return m
case reflect.Slice, reflect.Array:
var arr []interface{}
for i := 0; i arr = append(arr, toMap(v.Index(i)))
}
return arr
default:
if v.CanInterface() {
return v.Interface()
}
return nil
}
}
这个函数能处理常见结构体、指针、切片和基本类型,是通用序列化的基础模型。
基本上就这些。实际项目中建议优先使用json.Marshal配合结构体标签,只有在无法预知类型结构时才手动用reflect构建。注意性能开销和边界情况(如chan、func等不可序列化类型)。









