前言
Hey,大家好呀,我是码农,星期八。
反射在结构体中的应用,才是最广泛的!毕竟在Go中,是用结构体代替对象的!
所以最多的,最麻烦的,也是反射结构体,也是最灵活的!
反射在结构体的应用
上次讲的,只是在普通变量中的应用,相对来说,使用的场景不是太多。
但是反射在结构体中的应用,基本会贯穿整个Go语言基础。
示例代码
结构体
type Student struct { Name string `json:"name" describe:"姓名"` Age int `json:"age" describe:"年龄"` Gender bool `json:"gender" describe:"性别"` Hobby []string `json:"hobby" describe:"爱好"`}
main
func main() {
//实例化结构体
var s1 = Student{
Name: "张三",
Age: 18,
Gender: true,
Hobby: []string{"吃", "喝", "pia", "玩"},
}
var t = reflect.TypeOf(s1)
fmt.Println(t.Name()) //Student
fmt.Println(t.Kind()) //struct
fmt.Println(t.NumField()) //结果:4,表示多少个字段
for i := 0; i < t.NumField(); i++ {
field := t.Field(i)//每个结构体对象
/*
{Name string json:"name" describe:"姓名" 0 [0] false}
{Age int json:"age" describe:"年龄" 16 [1] false}
{Gender bool json:"gender" describe:"性别" 24 [2] false}
{Hobby []string json:"hobby" describe:"爱好" 32 [3] false}
*/
//fmt.Println(field)
fmt.Println("------")
fmt.Printf("field.Name:%v\n",field.Name)
fmt.Printf("field.Index:%v\n",field.Index)
fmt.Printf("field.Type:%v\n",field.Type)
fmt.Printf("field.Tag:%v\n",field.Tag.Get("describe"))
}
}
执行结果
单独反射指定字段信息
main代码
func main() { //实例化结构体 var s1 = Student{ Name: "张三", Age: 18, Gender: true, Hobby: []string{"吃", "喝", "pia", "玩"},} var t = reflect.TypeOf(s1) genderField, ok := t.FieldByName("Gender") if ok { fmt.Println(genderField.Name) //Gender fmt.Println(genderField.Index) //[2] fmt.Println(genderField.Type) //bool fmt.Println(genderField.Tag.Get("describe")) //性别 }}
ValueOf
上述的代码只能用的是TypeOf
,只能返回类型等信息,相对来说不是太智能,ValueOf
可以获取值,同样也能获取类型,相对来说比TypeOf
好一点。
示例代码
main
func main() { //实例化结构体 var s1 = Student{ Name: "张三", Age: 18, Gender: true, Hobby: []string{"吃", "喝", "pia", "玩"},} var v = reflect.ValueOf(s1) for i := 0; i < v.NumField(); i++ { field :=v.Field(i) fmt.Println("------") fmt.Printf("Kind:%v\n",field.Kind()) fmt.Printf("值:%v\n",field.Interface()) }}
执行结果
反射方法
上述我们反射的都是值,有没有反射是否可以反射函数,并且调用函数呢??
结构体和绑定函数代码
type Student struct {
Name string `json:"name" describe:"姓名"`
Age int `json:"age" describe:"年龄"`
Gender bool `json:"gender" describe:"性别"`
Hobby []string `json:"hobby" describe:"爱好"`
}
//无参方法
func (this Student) Say() {
fmt.Printf("我是%v,我的年龄是%v,我的性别是%v,我的爱好是%v\n", this.Name, this.Age, this.Gender, this.Hobby)
}
//有参数方法
func (this Student) Jump(distance int) {
fmt.Printf("我是%v,我跳远跳了%v米\n", this.Name, distance)
}
main
func main() { //实例化结构体 var s1 = Student{ Name: "张三", Age: 18, Gender: true, Hobby: []string{"吃", "喝", "pia", "玩"},} var t = reflect.TypeOf(s1) var v = reflect.ValueOf(s1) fmt.Println(v.NumMethod(),v.NumField()) for i := 0; i < v.NumMethod(); i++ { method := v.Method(i) fmt.Println("--------") fmt.Println(method)//0x48c4e0 函数地址 fmt.Println(method.Type())//func(int) 函数类型,形参和返回值 fmt.Println(t.Method(i).Name)//Jump,函数名,注意,由t来调用的 }}
执行结果
反射调用函数
func main() {
//实例化结构体
var s1 = Student{
Name: "张三",
Age: 18,
Gender: true,
Hobby: []string{"吃", "喝", "pia", "玩"},
}
var v = reflect.ValueOf(s1)
//通过反射调用函数
//调用Jump函数
//反射调用函数必须传一个参数,不管有没有形参都要传
//var args = []reflect.Value{}
//v.MethodByName("Say").Call(args)
//如果需要传参数
//参数需要用reflect.ValueOf(1) 强转一下
var args = []reflect.Value{reflect.ValueOf(2)}
v.MethodByName("Jump").Call(args)
}
注:注意第14行和20行代码区别,如果要传参数,参考第20行代码。
执行结果
反射注意事项
在平常开发中,尽量慎用反射,原因如下。
反射性能可能会比较低,毕竟是反正走的,一般比正向操作慢一两个级别。
反射越多,代码越烂,
TypeOf
和ValueOf
都有Kind
,很多情况是TypeOf
和ValueOf
混用的,所以对于基础不好的,极不友好。在Go中,是没有
try
的,如果反射没有处理好异常,程序会直接崩溃,可能在意想不到的地方。
有疑问加站长微信联系(非本文作者)