golang反射(一):反射结构体类型读取数据

先看下面的例子,通过反射一个结构体对象来获取信息。

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 对象中,下面简称 Value 对象和 Type 对象。
reflect.Value 是一个结构体。
reflect.Type 是一个接口,不是结构体。

根据上面的例子:

  1. 通过 reflect.ValueOf(v) 得到 v 的 Value 对象;
  2. 通过 v 的 Value 对象的 Kind() 方法(或者通过 v 的 Type 对象的 Kind() 方法,后面再讲如何获取 Type 对象)得到类型的种类,此处为 struct ,做一个限制;
  3. Value 对象的 NumField() 方法得到结构体中字段的个数,可以通过遍历得到每个字段;
  4. 结构体中字段是有顺序的,可以通过下标访问到,Value 对象的 Field(i) 方法依然返回 Value 对象,只不过这个对象存储的是第 i 个字段的信息。然后调用 Type() 方法得到字段的 Type 对象。调用 Type 对象的 String() 方法即可得到字段的数据类型,我们知道fmt包中的 Println(), Printf() 等函数会自动去调用对象的 String() 方法的;
  5. 字段的 Value 对象的 Interface() 方法可以得到字段的值;
  6. 而字段的名称是存在于结构体的 Type 对象中的,可以通过 reflect.TypeOf(v) 或者通过 v 的 Value 对象的 Type() 来得到。同样的,使用下标来访问字段,Type 对象的 Field(i) 方法返回 StructField 对象,存储着字段的 Type 信息。
  7. 对象的类型是否可导出不要紧,但是如果要通过反射访问某个字段,那么这个字段应该是可导出的,否则会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
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值