必须用 reflect.ValueOf(&structVar).Elem() 获取可寻址结构体反射对象,再遍历字段;需检查 v.Kind() == reflect.Struct、字段可导出(PkgPath == “”)和可设置(CanSet()),解析 tag 用 structTag.Get(),避免高频反射调用并缓存类型信息。
用 reflect.ValueOf 获取结构体值再遍历字段
直接对结构体变量调用 reflect.ValueOf 得到的是其值的反射对象,但必须确保传入的是地址(&structVar),否则无法修改字段,且部分字段(如未导出字段)在非指针情况下可能无法正确访问。若传入的是值而非指针,Value.NumField() 仍可读,但后续调用 SetXxx 会 panic。
常见错误现象:panic: reflect: reflect.Value.SetXxx called on zero Value 或字段值看似“空”——实际是因传了值副本,CanAddr() 为 false,导致 Field(i).Addr() 失败。
- 始终用
reflect.ValueOf(&myStruct).Elem()开始处理,确保可寻址 - 检查
v.Kind() == reflect.Struct再继续,避免对 map/slice 等误操作 - 遍历时用
v.Type().Field(i)拿StructField(含 tag、名字),用v.Field(i)拿对应Value
判断字段是否可导出、可设置、有特定 tag
Go 反射中“可导出”不等于“可设置”,而 tag 解析完全依赖字符串切分,没有内置 schema 验证。例如 `json:"name,omitempty"` 中的 omitempty 是 json 包自己解释的,reflect 只返回原始字符串。
使用场景:做通用序列化适配、ORM 字段映射、表单绑定时,需结合 tag 和可设置性决定是否写入值。