需先用 reflect.typeof 获取结构体类型再调 field(i) 得 structfield,用 kind() 判断基础类型;值操作须用 reflect.valueof 并配合 .int() 等方法;标签解析必须用 field.tag.get("key")。

用 reflect.TypeOf 和 reflect.ValueOf 区分类型与值
拿到结构体字段的类型信息,第一步是明确:类型(Type)和值(Value)必须分开获取。直接对结构体实例调用 reflect.TypeOf 返回的是整个结构体的类型,不是字段;而 reflect.ValueOf 返回的是运行时值对象,不带类型元数据。
正确做法是先用 reflect.TypeOf 获取结构体类型,再通过 .Field(i) 拿到字段的 reflect.StructField,它包含 Name、Type、Tag 等信息:
type User struct {
ID int `json:"id"`
Name string `json:"name"`
}
t := reflect.TypeOf(User{})
field := t.Field(0) // 第一个字段
fmt.Println(field.Name) // "ID"
fmt.Println(field.Type.Kind()) // int → <code>reflect.Int</code>
fmt.Println(field.Type.Name()) // "int"(基础类型返回空字符串,需用 <code>Kind()</code> 判断)
-
field.Type是reflect.Type,可继续调用.Kind()、.Name()、.PkgPath() - 导出字段才能被反射访问;未导出字段(小写开头)在
Field()中不可见 -
field.Type.Name()对内置类型(如int、string)返回空字符串,必须依赖.Kind()做判断
处理嵌套结构与指针字段的类型展开
字段类型可能是指针、切片、map 或嵌套结构体,field.Type 默认只给出顶层声明类型。要拿到实际元素类型(比如 *string 的基类型 string,或 []int 的元素类型 int),得手动展开:
- 用
.Elem()解引用指针:if field.Type.Kind() == reflect.Ptr { elemType := field.Type.Elem() } - 用
.Elem()获取切片/map 的元素类型:if field.Type.Kind() == reflect.Slice { elemType := field.Type.Elem() } - 用
.Key()和.Elem()分别获取 map 的 key/value 类型 - 嵌套结构体可用
.Field(i).Type递归访问,但注意检查Kind()是否为reflect.Struct
漏掉展开会导致误判 —— 比如把 *User 当成指针类型就结束,而没意识到它指向的仍是结构体,可继续反射其字段。
立即学习“go语言免费学习笔记(深入)”;
从结构体实例中读取字段值并做类型安全转换
仅知道类型还不够,常需读取运行时值并转成具体 Go 类型。这时必须用 reflect.ValueOf 获取值对象,再配合 .Interface() 或类型专属方法(如 .Int()、.String()):
u := User{ID: 123, Name: "Alice"}
v := reflect.ValueOf(u)
fieldVal := v.Field(0) // ID 字段的 Value
fmt.Println(fieldVal.Int()) // 123 —— 必须用 .Int(),不能直接 int(fieldVal)
fmt.Println(fieldVal.Interface()) // interface{}(123),可断言为 int
-
.Interface()是通用出口,但需要类型断言:id := fieldVal.Interface().(int),失败会 panic - 推荐优先用
.Int()、.String()、.Bool()等方法,它们在类型不匹配时 panic,比静默错误更易排查 - 若字段是指针(如
*string),v.Field(i)返回的是reflect.Valueof pointer,需先.Elem()再读值,否则.String()会 panic - 对非导出字段,
v.Field(i)返回 zero value 且不可设值,但可读(仅限包内反射,跨包不可见)
字段标签(Tag)解析必须用 StructField.Tag.Get
结构体字段上的反引号标签(如 `json:"name"`)不参与类型系统,反射中它只是字符串。必须显式调用 field.Tag.Get("json") 才能提取值:
-
field.Tag是reflect.StructTag类型,本质是字符串,但提供.Get(key)方法解析 - 标签键名区分大小写:
field.Tag.Get("JSON")≠field.Tag.Get("json") - 如果标签不存在,
.Get()返回空字符串,不会 panic - 不要自己用
strings.Split解析 tag 字符串 —— 它支持带空格、逗号分隔的选项(如`json:"name,omitempty"`),.Get()已处理这些细节
类型、值、标签三者在反射中是分离的入口,混用或跳步容易拿错信息。最常被忽略的是:没检查 Kind() 就直接调 .Elem(),或对未导出字段误以为能反射读写 —— 这些问题在运行时才暴露,调试成本高。










