任何方法都是有利有弊,通過(guò)反射的方法可以實(shí)現(xiàn)一個(gè)接口調(diào)用多個(gè)不同的函數(shù),但是使用反射某種程度上也是犧牲了部分性能。
下面通過(guò)幾組代碼通過(guò)代碼中的注釋解釋其原理,通過(guò)只調(diào)用FunCall執(zhí)行不同的函數(shù)
一 定義執(zhí)行函數(shù)
// 入庫(kù)前的判斷不再贅述
/**
*@Method db注冊(cè)方法
*@Params userName,password string
*@Return 返回執(zhí)行信息
*/
func Register(userName,password string)(res DBResult){
user := UserModel{
UserName: userName,
Password: password,
}
// 查詢用戶是否已經(jīng)存在
existed := user.userExisted()
if existed {
res.Suc = false
res.Msg = "用戶名已存在,請(qǐng)重新輸入"
return
}
// 不存在寫庫(kù)
err := mysqldb.WmConn().Create(&user).Error
if err != nil {
res.Suc = false
res.Msg = "注冊(cè)失敗,請(qǐng)重新嘗試"
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及方法解析函數(shù)
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:方法所需要的參數(shù)
*@Return 返回方法執(zhí)行結(jié)果slice和錯(cuò)誤
*/
func FuncCall(name string,params...interface{})(result []reflect.Value,err error){
if _,ok := funcs[name];!ok{
err = errors.New("請(qǐng)求路徑不存在")
return
}
// 通過(guò)反射獲取方法內(nèi)存地址
f := reflect.ValueOf(funcs[name])
// 對(duì)比傳入?yún)?shù)的長(zhǎng)度是否與通過(guò)反射取出的方法需要的參數(shù)數(shù)量是否一致
if len(params) != f.Type().NumIn(){
err = errors.New("傳入?yún)?shù)與需要的參數(shù)數(shù)量不一致")
return
}
// 創(chuàng)建一個(gè)切片用于放入?yún)?shù)
in := make([]reflect.Value,len(params))
// 初始化index
var i = 0
// 遍歷參數(shù)
for k,param := range params{
// 判斷應(yīng)位置的參數(shù)是否與需要的類型相同
if reflect.TypeOf(param) != f.Type().In(i){
err = errors.New("傳入?yún)?shù)類型與需要的不一致")
return
}
// 如果相同加入in切片
in[k] = reflect.ValueOf(param)
i ++
}
// call將in參數(shù)傳給f方法并執(zhí)行,返回結(jié)果賦值給result,該方法會(huì)執(zhí)行f(in[0],in[1],...)
result = f.Call(in)
return
}