Golang反射
Golang 反射
程序运行期间对程序本身进行访问和修改的能力
reflect.TypeOf() 获取对象的Type
reflect.ValueOf() 获取对象的Value
//TypeOf 这个函数返回任何表达式的类型
var a int = 64
s := reflect.TypeOf(a)
fmt.Println(s.Name()) //类型名称
fmt.Println(s.Kind()) //类型种类,底层的类型
fmt.Println(s) //int
//ValueOf 这个函数返回任何表达式的值
b := reflect.ValueOf(a)
fmt.Println(b.Kind())
fmt.Println(b) //64
TypeOf中还有两个方法 , Name获取类型的名称,kind 获取地城的类型种类
Go语言的反射中像数组、切片、Map、指针等类型的变量,它们的.Name()都是返回空。
kind的常用类型如下
– | – |
---|---|
Bool | 布尔型 |
Int | 有符号整型 |
int8 16 64 | 有符合8 16 64位整型 |
Uint | 无符号整型 |
Uint 8 16 64 | 无符号8 16 64位整型 |
UintPtr | 指针 |
Float 32 64 | 单精度和双精度浮点数 |
Complex64 128 | 64位和128位复数类型 |
Array | 数组 |
Chan | 通道 |
Func | 函数 |
interface | 接口 |
Map | 映射 |
Ptr | 指针 |
Slice | 切片 |
String | 字符串 |
Struct | 结构体 |
UnsafePointer | 底层指针 |
reflect.ValueOf()
提供的获取原始值的方法如下
方法 | 说明 |
---|---|
interface{} Interface() | 将值以interface{}类型返回,可以通过类型断言转换为指定类型 |
Int() int64 | 将值以int类型返回 |
Uint() uint64 | 将值以uint类型返回 |
Float() float64 | 将值以双精度float64类型返回 |
Book() bool | 将值以bool类型返回 |
Bytes() []bytes | 将值以字节数组[]bytes类型返回 |
String() string | 将值以字符串类型返回 |
通过反射设置变量的值
SetBool(x bool)
SetInt(x int64)
SetString(x string) 等
想要在函数中通过反射修改变量的值,需要注意函数参数传递的是值拷贝,必须传递变量地 址才能修改变量值。而反射中使用专有的 Elem()方法来获取指针对应的值。
//通过反射修改变量的值
var a int =32
v := reflect.ValueOf(&a)
if v.Kind() == reflect.Ptr && !v.Elem().CanSet() {
return
}
v.Elem().SetInt(86)
fmt.Println(a) //86
结构体反射
任意值通过 reflect.TypeOf()获得反射对象信息后,如果它的类型是结构体,可以通过反射值 对象(reflect.Type)的 NumField()和 Field()方法获得结构体成员的详细信息
方法 | 说明 |
---|---|
Field(i int) StructField | 根据索引,返回索引对应的结构体字段的信 息。 |
NumField() int | 返回结构体成员字段数量。 |
FieldByName(name string) (StructField, bool) | 根据给定字符串返回字符串对应的结构体字 段的信息。 |
FieldByIndex(index []int) StructField | 多层成员访问时,根据 []int 提供的每个结构 体的字段索引,返回字段的信息。 |
FieldByNameFunc(match func(string) bool) (StructField,bool) | 根据传入的匹配函数匹配需要的字段。 |
NumMethod() int | 返回该类型的方法集中方法的数目 |
Method(int) Method | 返回该类型方法集中的第 i 个方法 |
MethodByName(string)(Method, bool) | 根据方法名返回该类型方法集中的方法 |
//student结构体
type Student struct {
Name string `json:"name1" form:"username"`
Age int `json:"age"`
Score int `json:"score"`
}
func (s Student) GetInfo() string {
var str = fmt.Sprintf("姓名:%v 年龄:%v 成绩:%v", s.Name, s.Age, s.Score)
return str
}
func (s *Student) SetInfo(name string, age int, score int) {
s.Name = name
s.Age = age
s.Score = score
}
func (s Student) Print() {
fmt.Println("这是一个打印方法...")
}
//打印字段
func PrintStructField(s interface{}) {
//判断参数是不是结构体类型
t := reflect.TypeOf(s)
v := reflect.ValueOf(s)
if t.Kind() != reflect.Struct && t.Elem().Kind() != reflect.Struct {
fmt.Println("传入的参数不是一个结构体")
return
}
//1、通过类型变量里面的Field可以获取结构体的字段
field0 := t.Field(0)
fmt.Printf("%#v \n", field0) //reflect.StructField{Name:"Name", PkgPath:"", Type:(*reflect.rtype)(0x4adf20), Tag:"json:\"name\"", Offset:0x0, Index:[]int{0}, Anonymous:false}
fmt.Println("字段名称:", field0.Name)
fmt.Println("字段类型:", field0.Type)
fmt.Println("字段Tag:", field0.Tag.Get("json"))
fmt.Println("字段Tag:", field0.Tag.Get("form"))
//2、通过类型变量里面的FieldByName可以获取结构体的字段
fmt.Println("----------------------")
field1, ok := t.FieldByName("Age")
if ok {
fmt.Println("字段名称:", field1.Name)
fmt.Println("字段类型:", field1.Type)
fmt.Println("字段Tag:", field1.Tag.Get("json"))
}
//3、通过类型变量里面的NumField获取到该结构体有几个字段
var fieldCount = t.NumField()
fmt.Println("结构体有", fieldCount, "个属性")
//4、通过值变量获取结构体属性对应的值
fmt.Println(v.FieldByName("Name"))
fmt.Println(v.FieldByName("Age"))
fmt.Println("----------------------")
for i := 0; i < fieldCount; i++ {
fmt.Printf("属性名称:%v 属性值:%v 属性类型:%v 属性Tag:%v\n", t.Field(i).Name, v.Field(i), t.Field(i).Type, t.Field(i).Tag.Get("json"))
}
}
//打印执行方法
func PrintStructFn(s interface{}) {
t := reflect.TypeOf(s)
v := reflect.ValueOf(s)
if t.Kind() != reflect.Struct && t.Elem().Kind() != reflect.Struct {
fmt.Println("传入的参数不是一个结构体")
return
}
//1、通过类型变量里面的Method可以获取结构体的方法
method0 := t.Method(0) //和结构体方法的顺序没有关系,和结构体方法的ASCII有关系
fmt.Println(method0.Name) //GetInfo
fmt.Println(method0.Type) //func(main.Student) string
fmt.Println("--------------------------")
//2、通过类型变量获取这个结构体有多少个方法
method1, ok := t.MethodByName("Print")
if ok {
fmt.Println(method1.Name) //Print
fmt.Println(method1.Type) //func(main.Student)
}
fmt.Println("--------------------------")
//3、通过《值变量》执行方法 (注意需要使用值变量,并且要注意参数) v.Method(0).Call(nil) 或者v.MethodByName("Print").Call(nil)
// v.Method(1).Call(nil)
v.MethodByName("Print").Call(nil)
info1 := v.MethodByName("GetInfo").Call(nil)
fmt.Println(info1)
//4、执行方法传入参数 (注意需要使用《值变量》,并且要注意参数,接收的参数是[]reflect.Value的切片)
var params []reflect.Value
params = append(params, reflect.ValueOf("李四"))
params = append(params, reflect.ValueOf(23))
params = append(params, reflect.ValueOf(99))
v.MethodByName("SetInfo").Call(params) //执行方法传入参数
info2 := v.MethodByName("GetInfo").Call(nil)
fmt.Println(info2)
// 5、获取方法数量
fmt.Println("方法数量:", t.NumMethod())
}
func main() {
stu1 := Student{
Name: "小明",
Age: 15,
Score: 98,
}
// PrintStructField(stu1)
PrintStructFn(&stu1)
fmt.Printf("%#v\n", stu1)
}
Golang反射
http://www.jcwit.com/article/501/