任何方法都是有利有弊,通过反射的方法可以实现一个接口调用多个不同的函数,但是使用反射某种程度上也是牺牲了部分性能。
下面通过几组代码通过代码中的注释解释其原理,通过只调用FunCall执行不同的函数
一 定义执行函数
// 入库前的判断不再赘述
/**
*@Method db注册方法
*@Params userName,password string
*@Return 返回执行信息
*/
func Register(userName,password string)(res DBResult){
user := UserModel{
UserName: userName,
Password: password,
}
// 查询用户是否已经存在
existed := user.userExisted()
if existed {
res.Suc = false
res.Msg = "用户名已存在,请重新输入"
return
}
// 不存在写库
err := mysqldb.WmConn().Create(&user).Error
if err != nil {
res.Suc = false
res.Msg = "注册失败,请重新尝试"
return
}
res.Suc=true
res.Data=true
return
}
func (user *UserModel)userExisted() bool {
// 如果不存在found为true,存在为false
found := mysqldb.RmConn().Where(`user_name = ?`,user.UserName).First(&user).RecordNotFound()
if !found {
return true
}
return false
}
二 定义方法map及方法解析函数
package mapper
import (
"errors"
"micro-file-store/service/dbproxy/orm"
"reflect"
)
// 定义方法map
var funcs = map[string]interface{}{
"/user/register":orm.Register,
}
/**
*@Method 方法解析
*@Params name:方法map中的key,params:方法所需要的参数
*@Return 返回方法执行结果slice和错误
*/
func FuncCall(name string,params...interface{})(result []reflect.Value,err error){
if _,ok := funcs[name];!ok{
err = errors.New("请求路径不存在")
return
}
// 通过反射获取方法内存地址
f := reflect.ValueOf(funcs[name])
// 对比传入参数的长度是否与通过反射取出的方法需要的参数数量是否一致
if len(params) != f.Type().NumIn(){
err = errors.New("传入参数与需要的参数数量不一致")
return
}
// 创建一个切片用于放入参数
in := make([]reflect.Value,len(params))
// 初始化index
var i = 0
// 遍历参数
for k,param := range params{
// 判断应位置的参数是否与需要的类型相同
if reflect.TypeOf(param) != f.Type().In(i){
err = errors.New("传入参数类型与需要的不一致")
return
}
// 如果相同加入in切片
in[k] = reflect.ValueOf(param)
i ++
}
// call将in参数传给f方法并执行,返回结果赋值给result,该方法会执行f(in[0],in[1],...)
result = f.Call(in)
return
}