Go:反射
一、通过反射获取类型信息
在 Go 程序中,使用 reflect.TypeOf() 函数可以获得任意值的类型对象(reflect.Type),程序通过类型对象可以访问任意值的类型信息。
package main import ( "fmt" "reflect" ) func test1() { var a int t := reflect.TypeOf(a) fmt.Printf("name:%v kind:%v\n", t.Name(), t.Kind()) // name:int kind:int } func test2() { type User struct {} user := User{} t := reflect.TypeOf(user) fmt.Printf("name:%v kind:%v\n", t.Name(), t.Kind()) // name:User kind:struct } func main() { test1() test2() }
二、通过反射获取指针指向的元素类型
package main import ( "fmt" "reflect" ) func main() { // 声明一个空结构体 type User struct {} // 创建User的实例 user := &User{} // 获取结构体实例的反射类型对象 t := reflect.TypeOf(user) // 显示反射类型对象的名称和种类 fmt.Printf("name:'%v' kind:'%v'\n", t.Name(), t.Kind()) // name:'' kind:'ptr' // 获取指针类型的元素类型 e := t.Elem() // 显示指针变量指向元素的类型名称和种类 fmt.Printf("name:'%v' kind:'%v'\n", e.Name(), e.Kind()) // name:'User' kind:'struct' }
三、通过反射获取结构体的成员类型
任意值通过 reflect.TypeOf() 获得反射对象信息后,如果它的类型是结构体,可以通过反射值对象(reflect.Type)的 NumField() 和 Field() 方法获得结构体成员的详细信息。
package main import ( "fmt" "reflect" ) type User struct { Name string `json:"username"` Age int Salary float64 } func main() { user := User{"pd", 18, 9999.99} tf := reflect.TypeOf(user) // 遍历结构体所有成员 for i := 0; i < tf.NumField(); i++ { // 获取每个成员的结构体字段类型 fieldType := tf.Field(i) fmt.Printf("name:'%v' tag:'%v'\n", fieldType.Name, fieldType.Tag) // name:'Name' tag:'json:"username"' // name:'Age' tag:'' // name:'Salary' tag:'' } // 通过字段名, 找到字段类型信息 userType, ok := tf.FieldByName("Name") if ok { // 从tag中取出需要的tag fmt.Println(userType.Tag.Get("json")) // username } }
四、通过反射获取值信息
package main import ( "fmt" "reflect" ) func main() { // 声明整型变量a并赋初值 var a int a = 666 // 获取变量a的反射值对象 vf := reflect.ValueOf(a) // 将vf反射值对象以Interface{}类型取出, 通过类型断言转换为int类型 r1 := vf.Interface().(int) // 将vf反射值对象以int64类型取出 r2 := vf.Int() // 强制类型转换为int类型 r3 := int(r2) fmt.Printf("r1值:%v r1类型:%T\n", r1, r1) // r1值:666 r1类型:int fmt.Printf("r2值:%v r2类型:%T\n", r2, r2) // r2值:666 r2类型:int64 fmt.Printf("r3值:%v r3类型:%T\n", r3, r3) // r3值:666 r3类型:int }
五、通过反射访问结构体成员的值
package main import ( "fmt" "reflect" ) type User struct { Name string Age int Salary float64 } func main() { user := User{"pd", 18, 9999.99} vf := reflect.ValueOf(user) // 获取字段数量 fmt.Printf("NumField:%v\n", vf.NumField()) // NumField:3 // 获取索引为2的字段 field := vf.Field(2) fmt.Println(field.Type()) // float64 // 根据名字查找字段 fbn := vf.FieldByName("Name") fmt.Println(fbn.Type()) // string // 根据索引查找字段 fbi := vf.FieldByIndex([]int{1}) fmt.Println(fbi.Type()) // int }
六、判断反射值的空和有效性
package main import ( "fmt" "reflect" ) func main() { // *int的空指针 var a *int fmt.Println(reflect.ValueOf(a).IsNil()) // true // nil值 fmt.Println(reflect.ValueOf(nil).IsValid()) // false // 实例化一个结构体 s := struct{}{} // 尝试从结构体中查找一个不存在的字段 fmt.Println(reflect.ValueOf(s).FieldByName("").IsValid()) // false // 尝试从结构体中查找一个不存在的方法 fmt.Println(reflect.ValueOf(s).MethodByName("").IsValid()) // false }
七、通过反射修改变量的值
package main import ( "fmt" "reflect" ) func main() { // 声明整型变量a并赋初值 var a int var b string a = 100 b = "哈哈哈" // 获取变量a、b的反射值对象(a、b的地址) vfa := reflect.ValueOf(&a) vfb := reflect.ValueOf(&b) // 取出a、b地址的元素(值) vfae := vfa.Elem() vfbe := vfb.Elem() // 修改a、b的值 vfae.SetInt(200) vfbe.SetString("嘻嘻嘻") // 打印a、b的值 fmt.Println(a, b) // 200 嘻嘻嘻 }
package main import ( "fmt" "reflect" ) type User struct { Name string Age int } func main() { user := User{"pd", 18} vf := reflect.ValueOf(&user) // 取出User实例地址的元素 vfe := vf.Elem() // 获取Name字段的值 name := vfe.FieldByName("Name") // 修改此实例(对象)对应字段的值 name.SetString("佩奇") fmt.Println(user) // {佩奇 18} }
八、通过类型信息创建实例
package main import ( "fmt" "reflect" ) func main() { var a int // 取变量a的反射类型对象 tf := reflect.TypeOf(a) // 根据反射类型对象创建这个类型的实例值,值以 reflect.Value 类型返回 obj := reflect.New(tf) // 输出类型和种类 fmt.Printf("type:%v kind:%v\n", obj.Type(), obj.Kind()) // type:*int kind:ptr }
九、通过反射调用函数、方法
package main import ( "fmt" "reflect" ) // add函数 func add(a, b int) int { return a + b } func main() { // 将函数包装为反射值对象 vf := reflect.ValueOf(add) // 构造函数参数, 传入两个整型值 paramList := []reflect.Value{reflect.ValueOf(10), reflect.ValueOf(20)} // 反射调用函数 retList := vf.Call(paramList) // 获取第一个返回值, 取整数值 fmt.Println(retList[0].Int()) // 30 }
package main import ( "fmt" "reflect" ) type User struct { Name string } func (u *User) Hello(name string) { fmt.Printf("%s对%s打了一个招呼...\n", u.Name, name) // pd对佩奇打了一个招呼... } func main() { user := User{"pd"} vf := reflect.ValueOf(&user) method := vf.MethodByName("Hello") // 方式1 // args := []reflect.Value{reflect.ValueOf("佩奇")} // 方式2 var args []reflect.Value args = append(args, reflect.ValueOf("佩奇")) // 调用方法 method.Call(args) }