先看下面的例子,通过反射一个结构体对象来获取信息。
type Man struct {
Id int
Name string
}
m := Man{1, "a"}
func(v interface{}){
getValue := reflect.ValueOf(v)
if getValue.Kind() != reflect.Struct {
panic("need struct kind")
}
getType := reflect.TypeOf(v)
// 或者 getType := getValue.Type()
for i := 0; i < getValue.NumField(); i++ {
fmt.Printf("name: %s, type: %s, value: %v\n", getType.Field(i).Name, getValue.Field(i).Type(), getValue.Field(i).Interface())
}
}(m)
打印信息
name: Id, type: int, value: 1
name: Name, type: string, value: a
reflect.Valuereflect.Type
根据上面的例子:
- 通过 reflect.ValueOf(v) 得到 v 的 Value 对象;
- 通过 v 的 Value 对象的 Kind() 方法(或者通过 v 的 Type 对象的 Kind() 方法,后面再讲如何获取 Type 对象)得到类型的种类,此处为 struct ,做一个限制;
- Value 对象的 NumField() 方法得到结构体中字段的个数,可以通过遍历得到每个字段;
- 结构体中字段是有顺序的,可以通过下标访问到,Value 对象的 Field(i) 方法依然返回 Value 对象,只不过这个对象存储的是第 i 个字段的信息。然后调用 Type() 方法得到字段的 Type 对象。调用 Type 对象的 String() 方法即可得到字段的数据类型,我们知道fmt包中的 Println(), Printf() 等函数会自动去调用对象的 String() 方法的;
- 字段的 Value 对象的 Interface() 方法可以得到字段的值;
- 而字段的名称是存在于结构体的 Type 对象中的,可以通过 reflect.TypeOf(v) 或者通过 v 的 Value 对象的 Type() 来得到。同样的,使用下标来访问字段,Type 对象的 Field(i) 方法返回 StructField 对象,存储着字段的 Type 信息。
- 对象的类型是否可导出不要紧,但是如果要通过反射访问某个字段,那么这个字段应该是可导出的,否则会panic。
看着有点绕,实则是 reflect 包的方法定义的具有一定的迷惑性。
// A StructField describes a single field in a struct.
type StructField struct {
// Name is the field name.
Name string
// PkgPath is the package path that qualifies a lower case (unexported)
// field name. It is empty for upper case (exported) field names.
// See https://golang.org/ref/spec#Uniqueness_of_identifiers
PkgPath string
Type Type // field type
Tag StructTag // field tag string
Offset uintptr // offset within struct, in bytes
Index []int // index sequence for Type.FieldByIndex
Anonymous bool // is an embedded field
}
type Value struct {
typ *rtype
ptr unsafe.Pointer
flag
}
type Type interface {
Align() int
FieldAlign() int
Method(int) Method
MethodByName(string) (Method, bool)
NumMethod() int
Name() string
PkgPath() string
Size() uintptr
String() string
Kind() Kind
Implements(u Type) bool
AssignableTo(u Type) bool
ConvertibleTo(u Type) bool
Comparable() bool
Bits() int
ChanDir() ChanDir
IsVariadic() bool
Elem() Type
Field(i int) StructField
FieldByIndex(index []int) StructField
FieldByName(name string) (StructField, bool)
FieldByNameFunc(match func(string) bool) (StructField, bool)
In(i int) Type
Key() Type
Len() int
NumField() int
NumIn() int
NumOut() int
Out(i int) Type
common() *rtype
uncommon() *uncommonType
}