反射能让我们更简便地获得一个对象的类型、值,如果对象是结构体还能获得它的属性、方法。
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
}
type Value struct {
typ *rtype
ptr unsafe.Pointer
flag
}
下文再介绍 reflect.Value 常用方法。
1、ValueOf () 从接口变量到反射对象
函数:
func TypeOf(i interface{}) Type
func ValueOf(i interface{}) Value
例子:
var age interface{} = 20
fmt.Println("age: ", age)
// 1、TypeOf ValueOf 从接口变量到反射对象
t := reflect.TypeOf(age)
v := reflect.ValueOf(age)
fmt.Printf("TypeOf %T \n", t)
fmt.Printf("ValueOf %T \n", v)
// TypeOf *reflect.rtype
// ValueOf reflect.Value
2、Interface() 从反射对象到接口变量
函数:
func (v Value) Interface() (i interface{})
例子:
// 2、Interface 从反射对象到接口变量
v = reflect.ValueOf(age)
i := v.Interface()
fmt.Printf("Interface %T %v\n", i, i)
// Interface int 20
最后转换后的对象,静态类型为 interface{} ,如果要转成最初的原始类型,需要再类型断言转换一下
i := v.Interface().(int)
3、Elem() 获取指针指向的数据(用来修改反射数据)
函数:
例子:
// 3、Elem 获取指针指向的数据(用来修改反射数据)
v1 := reflect.ValueOf(&age)
fmt.Println("v1 可写性为:", v1.CanSet())
v2 := v1.Elem()
fmt.Println("v2 可写性为:", v2.CanSet())
// v1 可写性为: false
// v2 可写性为: true
由于go语言函数是值传递,所以想要修改值必须得传入指针变量。
4、SetString() 设置值
函数:
func (v Value) SetString(x string)
例子:
// 4、SetString() 设置值
name := "hello"
v1 = reflect.ValueOf(&name)
v2 = v1.Elem()
v2.SetString("world")
fmt.Printf("SetString %T %v\n", name, name)
// SetString string world
5、Kind() 获取类别(相对Type 更广义)
函数:
例子:
// 5、Kind() 获取类别(相对Type 更广义)
m := People{}
t = reflect.TypeOf(m)
fmt.Printf("Type: %v\n",t)
fmt.Printf("Kind: %v\n",t.Kind())
// Type: main.People
// Kind: struct
6、Int()、Float()、String()、Bool()、Interface() 类型转换
函数:
func (v Value) Int() int64
例子:
// 6、Int()、Float()、String()、Bool()、Interface() 类型转换
age = 88
ageV := reflect.ValueOf(age)
fmt.Printf("Int 转换前, type: %T, value: %v \n", ageV, ageV)
ageV2 := ageV.Int()
fmt.Printf("Int 转换后, type: %T, value: %v \n", ageV2, ageV2)
// Int 转换前, type: reflect.Value, value: 88
// Int 转换后, type: int64, value: 88
7、NumField() 获取结构体属性个数
函数:
例子:
// 7、NumField() 获取结构体属性个数
p := People{name: "hss", age: 27}
pv := reflect.ValueOf(p)
fmt.Printf("NumField: %v\n", pv.NumField())
// NumField: 2
8、Field() 获取结构体属性
函数:
func (v Value) Field(i int) Value
例子:
// 8、Field() 获取结构体属性
p = People{name: "hss", age: 27}
pv = reflect.ValueOf(p)
fmt.Printf("Field 1: %v\n", pv.Field(0))
fmt.Printf("Field 2: %v\n", pv.Field(1))
// Field 1: hss
// Field 2: 27
9、NumMethod() 获取结构体方法个数
函数:
func (v Value) NumMethod() int
例子:
// 9、NumMethod() 获取结构体方法个数
p = People{name: "hss", age: 27}
pv = reflect.ValueOf(p)
fmt.Printf("NumMethod: %v\n", pv.NumMethod())
// NumMethod: 2
10、Method() 获取结构体方法
函数:
func (v Value) Method(i int) Value
例子:
// 10、Method() 获取结构体方法
p = People{name: "hss", age: 27}
tp := reflect.TypeOf(p)
fmt.Printf("Method 1: %v\n", tp.Method(0).Name)
fmt.Printf("Method 2: %v\n", tp.Method(1).Name)
// Method 1: SayBye
// Method 2: SayHello
优点:
1、避免硬编码
2、某种情况下 方便辅助一些类型判断
3、某种情况下 方便辅助根据对象获取属性和方法
缺点:
1、有点抽象难理解
2、学习成本高可读性差
3、运行效率低、性能不佳