注意通过指针变量获取的变量是地址
//指针变量的kind
fmt.Printf("%v\n", reflect.TypeOf(&student).Kind()) //ptr
//指针变量的 type
fmt.Printf("%T\n", &student) //*main.Student
//区别于student.Name == (*student).Name
fmt.Printf("%v\n", &student.Name) //0xc0000044a0
//指针变量的type
fmt.Printf("%T\n", &student.Name) //*string
反射可以在运行时动态获取变量的各种信息, 比如变量的类型(type), 类别(kind),type和kind可能一样
type -> int,float,main.Student, *main.Student
kind - > int, float, struct, ptr
func main() {
var name string = "咖啡色的羊驼"
fmt.Printf("%v\n", reflect.TypeOf(name)) //string
fmt.Printf("%v\n", reflect.TypeOf(name).Kind())//string
s := stud.Student{
Name: "张三",
Age: 12,
}
fmt.Printf("%v\n", reflect.TypeOf(s))//stud.Student
fmt.Printf("%v\n", reflect.TypeOf(s).Kind())//struct
}
如果是结构体变量, 还可以获取到结构体本身的信息(包括结构体的字段, 方法)
type Student struct {
Name string
Age int
}
func main() {
student := Student{
Name: "张三",
Age: 12,
}
val := reflect.ValueOf(student)
fmt.Printf("%T\n", val)
//相当于Java的getField()
name := val.FieldByName("Name")
//相当于Java的get, Java中String为引用类型
fmt.Println(name.String())
age := val.FieldByName("Age")
fmt.Println(age.Int())
//相当于Java的newInstance()
instance := val.Interface()
fmt.Println(instance)
//类似Java返回的对象是Object, 需要强转
stu:= instance.(Student)
fmt.Println(stu.Name)
fmt.Println(stu.Age)
}
方法和字段需要对外公开才能获取到
获取类别
func main() {
student := Student{
Name: "张三",
Age: 12,
}
rVal := reflect.ValueOf(student)
rTyp := reflect.TypeOf(student)
//相当于Java中getTypeName()
fmt.Println(rVal.Kind())
fmt.Println(rTyp.Kind())
}
获取字段
func main() {
stu := Student{
Name: "张三",
Age: 12,
Gender: false,
}
rVal := reflect.ValueOf(stu)
kind := rVal.Kind()
typ := rVal.Type()
if kind!= reflect.Struct {
fmt.Println("error")
return
}
//如果操作对象不是结构体就会报错
for i := 0; i < rVal.NumField(); i++ {
val := rVal.Field(i)
//只有type才有Tag
tag := typ.Field(i).Tag.Get("json")
//*(*string)(v.ptr)将ptr转为*string,然后取值
fmt.Println(val,tag)
}
}
如果修改值, 传入的必需是指针类型, 因为传入基本类型,通过值传递,函数内的对象地址不同
func reflect02(inter interface{}) {
rVal := reflect.ValueOf(inter)
fmt.Printf("%T\n", rVal)
//由于是值传递,这里对象的地址与外部的不同
fmt.Printf("%v\n", rVal)//0xc00003a1f0
fmt.Printf("%v\n", rVal.Kind())
//Elem()获取指针指向的对象
//rVal是地址.Elem()相当于取地址符*
rVal.Elem().SetInt(100)
}
func main() {
var num int = 12
fmt.Println(num)
//0xc00000a0f8
fmt.Println(&num)
reflect02(&num)
fmt.Println(num)
}
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
func reflect01(inter interface{}) {
rVal := reflect.ValueOf(inter)
fmt.Println(rVal.Kind())
//Elem方法能返回指针变量指向的值
age := rVal.Elem().FieldByName("Age")
age.SetInt(19)
}
func main() {
student := Student{
Name: "张三",
Age: 12,
}
fmt.Println(student)
//如果想调用结构体中的指针变量, 无需使用取地址符
reflect01(&student)
fmt.Println(student)
}
invoke方法
type Student struct {
Name string `json:"name"`
Age int `json:"age"`
Gender bool `json:"gender"`
}
func (s Student) Add(a, b int) int {
fmt.Println("invoke add")
return a + b
}
func (s Student) Blank() {
fmt.Println("blank method")
}
func (this *Student) SetName(name string) {
this.Name = name
}
func main() {
stu := Student{
Name: "张三",
Age: 12,
Gender: false,
}
rVal := reflect.ValueOf(stu)
kind := rVal.Kind()
if kind!= reflect.Struct {
fmt.Println("error")
return
}
//rVal.Method()如果通过这种方式获取到的方法,方法按照字典序排序
//同样的方法也需要公开
blank := rVal.MethodByName("Blank")
blank.Call(nil)
add := rVal.MethodByName("Add")
//函数返回一个切片
res := add.Call(append([]reflect.Value{}, reflect.ValueOf(1), reflect.ValueOf(2)))
fmt.Println(res[0])
set := rVal.MethodByName("SetName")
set.Call(append([]reflect.Value{reflect.ValueOf("李四")}))
fmt.Println(stu)
}
func main() {
stu := Student{
Name: "张三",
Age: 12,
Gender: false,
}
clazz := reflect.ValueOf(&stu)
typ := reflect.TypeOf(&stu)
if clazz.Kind() != reflect.Ptr {
fmt.Println("不是指针,不能修改值")
return
}
//这里要通过Elem()获取到地址指向的对象,才能操作
num := clazz.Elem().NumField()
for i := 0; i < num; i++ {
tag := typ.Elem().Field(i).Tag.Get("json")
if tag == "name" {
clazz.Elem().Field(i).SetString("李四")
}
}
fmt.Println(stu)
}
原文:https://www.cnblogs.com/kikochz/p/13511074.html