反射
反射是指在程序运行期对程序本身进行访问和修改的能力
变量的内在机制
变量包含类型信息和值信息 var arr [10]int arr[0] = 10
类型信息:是静态的元信息,是预先定义好的
值信息:是程序运行过程中动态改变的
反射的使用
reflect包封装了反射相关的方法
获取类型信息:reflect.TypeOf,是静态的
获取值信息:reflect.ValueOf,是动态的
示例1
package mainimport ("fmt""reflect"
)type User struct {Name stringAge int
}func main() {u := User{"tom", 27}// 获取类型的具体信息t := reflect.TypeOf(u)fmt.Println(t.Name()) // Userfmt.Println(t.Kind()) // structv := reflect.ValueOf(u)fmt.Println(v)
}
输出:
User
struct
{tom 27}
示例2
反射可以在运行时动态获取程序的各种详细信息
反射获取interface类型信息
package mainimport ("fmt""reflect"
)//反射获取interface类型信息func reflect_type(a interface{}) {t := reflect.TypeOf(a)fmt.Println("类型是:", t)// kind()可以获取具体类型k := t.Kind()fmt.Println(k)switch k {case reflect.Float64:fmt.Printf("a is float64\n")case reflect.String:fmt.Println("string")}
}func main() {var x float64 = 3.4reflect_type(x)
}
输出
类型是: float64
float64
a is float64
示例3
反射获取interface值信息
package mainimport ("fmt""reflect"
)//反射获取interface值信息func reflect_value(a interface{}) {v := reflect.ValueOf(a)fmt.Println(v)k := v.Kind()fmt.Println(k)switch k {case reflect.Float64:fmt.Println("a是:", v.Float())}
}func main() {var x float64 = 3.4reflect_value(x)
}
输出
3.4
float64
a是: 3.4
示例4
反射修改值信息
package mainimport ("fmt""reflect"
)// 反射修改值
func reflect_set_value(a interface{}) {v := reflect.ValueOf(a)k := v.Kind()switch k {case reflect.Float64:// 反射修改值v.SetFloat(6.9)fmt.Println("a is ", v.Float())case reflect.Ptr:// Elem()获取地址指向的值v.Elem().SetFloat(7.9)fmt.Println("case:", v.Elem().Float())// 地址fmt.Println(v.Pointer())}
}func main() {var x float64 = 3.4fmt.Println("main:", x)// 反射认为下面是指针类型,不是float类型reflect_set_value(&x)fmt.Println("main:", x)
}
输出
main: 3.4
case: 7.9
1374390181912
main: 7.9
示例5
查看类型、字段和方法
package mainimport ("fmt""reflect"
)// 定义结构体
type User struct {Id intName stringAge int
}// 绑方法
func (u User) Hello() {fmt.Println("Hello")
}// 传入interface{}
func Poni(o interface{}) {t := reflect.TypeOf(o)fmt.Println("类型:", t)fmt.Println("字符串类型:", t.Name())// 获取值v := reflect.ValueOf(o)fmt.Println(v)// 可以获取所有属性// 获取结构体字段个数:t.NumField()for i := 0; i < t.NumField(); i++ {// 取每个字段f := t.Field(i)fmt.Printf("%s : %v", f.Name, f.Type)// 获取字段的值信息// Interface():获取字段对应的值val := v.Field(i).Interface()fmt.Println("val :", val)}fmt.Println("=================方法====================")for i := 0; i < t.NumMethod(); i++ {m := t.Method(i)fmt.Println(m.Name)fmt.Println(m.Type)}}func main() {u := User{1, "zs", 20}Poni(u)
}
输出
类型: main.User
字符串类型: User
{1 zs 20}
Id : intval : 1
Name : stringval : zs
Age : intval : 20
=================方法====================
Hello
func(main.User)
示例6
查看匿名字段
package mainimport ("fmt""reflect"
)// 定义结构体
type User struct {Id intName stringAge int
}// 匿名字段
type Boy struct {UserAddr string
}func main() {m := Boy{User{1, "zs", 20}, "bj"}t := reflect.TypeOf(m)fmt.Println(t)// Anonymous:匿名fmt.Printf("%#v\n", t.Field(0))// 值信息fmt.Printf("%#v\n", reflect.ValueOf(m).Field(0))
}
输出
main.Boy
reflect.StructField{Name:"User", PkgPath:"", Type:(*reflect.rtype)(0x102b8b100), Tag:"", Offset:0x0, Index:[]int{0}, Anonymous:true}
main.User{Id:1, Name:"zs", Age:20}
示例7
修改结构体的值
package mainimport ("fmt""reflect"
)// 定义结构体
type User struct {Id intName stringAge int
}// 修改结构体值
func SetValue(o interface{}) {v := reflect.ValueOf(o)// 获取指针指向的元素v = v.Elem()// 取字段f := v.FieldByName("Name")if f.Kind() == reflect.String {f.SetString("kuteng")}
}func main() {u := User{1, "5lmh.com", 20}SetValue(&u)fmt.Println(u)
}
输出
{1 kuteng 20}
示例8
调用方法
package mainimport ("fmt""reflect"
)// 定义结构体
type User struct {Id intName stringAge int
}func (u User) Hello(name string) {fmt.Println("Hello:", name)
}func main() {u := User{1, "5lmh.com", 20}v := reflect.ValueOf(u)// 获取方法m := v.MethodByName("Hello")// 构建一些参数args := []reflect.Value{reflect.ValueOf("6666")}// 没参数的情况下:var args2 []reflect.Value// 调用方法,需要传入方法的参数m.Call(args)
}
输出
Hello: 6666
示例9
获取字段的tag
package mainimport ("fmt""reflect"
)type Student struct {Name string `json:"name1" db:"name2"`
}func main() {var s Studentv := reflect.ValueOf(&s)// 类型t := v.Type()// 获取字段f := t.Elem().Field(0)fmt.Println(f.Tag.Get("json"))fmt.Println(f.Tag.Get("db"))
}
输出
name1
name2
参考
https://www.topgoer.com/%E5%B8%B8%E7%94%A8%E6%A0%87%E5%87%86%E5%BA%93/%E5%8F%8D%E5%B0%84.html