随学随记,留备查
1、初学web设计,暂不想使用第三方库;于是乎HandleFunc()写的满屏都是……就想着模拟MVC思想,根据URL的路径自动调用指定的控制器方法,岂不是很好;
2、尝试使用Go的反射功能,初步实现了原理算法;
3、需要引入“reflect”包,使用reflect.ValueOf()方法,这里必须传入参数地址,否则其返回的reflect.Value类型只能查询到静态声明的方法,不能得到动态绑定的方法;
4、即使传入参数地址,其返回的reflect.Value类型,也得不到方法名;Go的意思应该是值和类型分开处理,在类型里面才有名称等信息;
4、需要再次调用返回值的Type()方法,这样就可以查询方法名称;
5、然后将方法名称和方法指针存入Map中,后续通过Map[name]的方式根据方法名字符串调用对应的方法;
package main import ( "fmt" "reflect" ) //定义控制器函数Map类型,便于后续快捷使用 type ControllerMapsType map[string]reflect.Value //声明控制器函数Map类型变量 var ControllerMaps ControllerMapsType //定义路由器结构类型 type Routers struct { } //为路由器结构附加功能控制器函数,值传递 func (this *Routers) Login(msg string) { fmt.Println("Login:", msg) } //为路由器结构附加功能控制器函数,引用传递 func (this *Routers) ChangeName(msg *string) { fmt.Println("ChangeName:", *msg) *msg = *msg + " Changed" } func main() { var ruTest Routers crMap := make(ControllerMapsType, 0) //创建反射变量,注意这里需要传入ruTest变量的地址; //不传入地址就只能反射Routers静态定义的方法 vf := reflect.ValueOf(&ruTest) vft := vf.Type() //读取方法数量 mNum := vf.NumMethod() fmt.Println("NumMethod:", mNum) //遍历路由器的方法,并将其存入控制器映射变量中 for i := 0; i < mNum; i++ { mName := vft.Method(i).Name fmt.Println("index:", i, " MethodName:", mName) crMap[mName] = vf.Method(i) //<<< } //演示 testStr := "Hello Go" //创建带调用方法时需要传入的参数列表 parms := []reflect.Value{reflect.ValueOf(testStr)} //使用方法名字符串调用指定方法 crMap["Login"].Call(parms) //创建带调用方法时需要传入的参数列表 parms = []reflect.Value{reflect.ValueOf(&testStr)} //使用方法名字符串调用指定方法 crMap["ChangeName"].Call(parms) //可见,testStr的值已经被修改了 fmt.Println("testStr:", testStr) }
有疑问加站长微信联系(非本文作者)