Golang反射reflect机制用法
重点:
- 转换的时候,如果转换的类型不完全符合,则直接panic,类型要求非常严格!
- 转换的时候,要区分是指针还是指
- 也就是说反射可以将“反射类型对象”再重新转换为“接口类型变量”
package main
import (
"fmt"
"reflect"
)
type Bookss struct {
auth string
}
type User struct {
Id int
Name string
Age int
}
func (this User) CallMethod() {
fmt.Println("user is called ...")
fmt.Printf("%v \n", this)
}
func DoFiledAndMethod(input interface{}) {
// 获取input的type
inputType := reflect.TypeOf(input)
fmt.Println("inputType is :", inputType.Name())
// 获取input的value
inputValue := reflect.ValueOf(input)
fmt.Println("inputValue is :", inputValue)
// 通过type 获取里面的字段
// 1.获取interface的reflect.Type,通过Type得到NumField,进行遍历
// 2.得到每个field的数据类型
// 3.通过filed有一个Interface()方法得到对应的value
for i := 0; i < inputType.NumField(); i++ {
filed := inputType.Field(i)
value := inputValue.Field(i).Interface()
fmt.Printf("%s: %v = %v \n", filed.Name, filed.Type, value)
}
// 通过type 获取里面的方法,调用它
//1. 先获取interface的reflect.Type,然后通过NumMethod进行遍历
//2. 再分别通过reflect.Type的Method获取对应的真实的方法(函数)
//3. 最后对结果取其Name和Type得知具体的方法名
//4. 也就是说反射可以将“反射类型对象”再重新转换为“接口类型变量”
//5. struct 或者 struct 的嵌套都是一样的判断处理方式
for i := 0; i < inputType.NumMethod(); i++ {
m := inputType.Method(i)
fmt.Printf("%s: %v \n", m.Name, m.Type)
}
}
func main() {
// ================================================================================
//var s = []int{1, 2}
//xx := reflect.ValueOf(s)
//fmt.Println(xx)
//yy := reflect.TypeOf(s)
//fmt.Println(yy)
// ================================================================================
//book := Bookss{"张三"}
//
//xx := reflect.ValueOf(book)
//fmt.Println(xx)
//
//yy := reflect.TypeOf(book)
//fmt.Println(yy)
// ================================================================================
//num := false
//fmt.Println(reflect.TypeOf(num))
//fmt.Println(reflect.ValueOf(num))
// ================================================================================
//user := User{1, "张三", 30}
//DoFiledAndMethod(user)
// ================================================================================
var num float64 = 1.2345
pointer := reflect.ValueOf(&num)
value := reflect.ValueOf(num)
// 可以理解为“强制转换”,但是需要注意的时候,转换的时候,如果转换的类型不完全符合,则直接panic
// Golang 对类型要求非常严格,类型一定要完全符合
// 如下两个,一个是*float64,一个是float64,如果弄混,则会panic
convertPointer := pointer.Interface().(*float64)
convertValue := value.Interface().(float64)
fmt.Println(convertPointer)
fmt.Println(convertValue)
}
通过反射调用方法
- 要通过反射来调用起对应的方法,必须要先通过reflect.ValueOf(interface)来获取到reflect.Value,得到“反射类型对象”后才能做下一步处理
- reflect.Value.MethodByName这.MethodByName,需要指定准确真实的方法名字,如果错误将直接panic,MethodByName返回一个函数值对应的reflect.Value方法的名字。
- []reflect.Value,这个是最终需要调用的方法的参数,可以没有或者一个或者多个,根据实际参数来定。
- reflect.Value的 Call 这个方法,这个方法将最终调用真实的方法,参数务必保持一致,如果reflect.Value’Kind不是一个方法,那么将直接panic。
- 本来可以用u.ReflectCallFuncXXX直接调用的,但是如果要通过反射,那么首先要将方法注册,也就是MethodByName,然后通过反射调用methodValue.Call
package main
import (
"fmt"
"reflect"
)
type Users struct {
Id int
Name string
Age int
}
// 有参数的方法
func (u Users) ReflectCallFuncHasArgs(name string, age int) {
fmt.Println("ReflectCallFuncHasArgs name: ", name, ", age:", age, "and origal User.Name:", u.Name)
}
// 没有参数的方法
func (u Users) ReflectCallFuncNoArgs() {
fmt.Println("ReflectCallFuncNoArgs")
}
// 如何通过反射来进行方法的调用?
// 本来可以用u.ReflectCallFuncXXX直接调用的,但是如果要通过反射,那么首先要将方法注册,也就是MethodByName,然后通过反射调动mv.Call
func main() {
user := Users{1, "Allen.Wu", 25}
// 1. 要通过反射来调用起对应的方法,必须要先通过reflect.ValueOf(interface)来获取到reflect.Value,得到“反射类型对象”后才能做下一步处理
getValue := reflect.ValueOf(user)
// 一定要指定参数为正确的方法名
// 2. 先看看带有参数的调用方法
methodValue := getValue.MethodByName("ReflectCallFuncHasArgs")
args := []reflect.Value{reflect.ValueOf("wudebao"), reflect.ValueOf(30)}
methodValue.Call(args)
// 一定要指定参数为正确的方法名
// 3. 再看看无参数的调用方法
methodValue = getValue.MethodByName("ReflectCallFuncNoArgs")
args = make([]reflect.Value, 0)
methodValue.Call(args)
}
Golang反射解析结构体标签Tag
package main
import (
"fmt"
"reflect"
)
type resume struct {
Name string `info:"name" doc:"我的名字"`
Sex string `info:"sex" doc:"我的性别"`
}
func findTag(str interface{}) {
t := reflect.TypeOf(str).Elem()
for i := 0; i < t.NumField(); i++ {
tagInfo := t.Field(i).Tag.Get("info")
tagDoc := t.Field(i).Tag.Get("doc")
fmt.Println("info:", tagInfo, "tagDoc:", tagDoc)
}
}
func main() {
re := resume{}
findTag(&re)
}
Golang结构体标签在json中的应用
package main
import (
"fmt"
"reflect"
)
type resume struct {
Name string `info:"name" doc:"我的名字"`
Sex string `info:"sex" doc:"我的性别"`
}
func findTag(str interface{}) {
t := reflect.TypeOf(str).Elem()
for i := 0; i < t.NumField(); i++ {
tagInfo := t.Field(i).Tag.Get("info")
tagDoc := t.Field(i).Tag.Get("doc")
fmt.Println("info:", tagInfo, "tagDoc:", tagDoc)
}
}
func main() {
re := resume{}
findTag(&re)
}
结构体标签的应用
1.json编码、解码
2.orm映射关系