Go反射-通过反射调用结构体的方法(带入参)

使用反射前,我们需要提前做好映射配置

papckage_struct_relationship.go

go 复制代码
package reflectcommon

import (
	api "template/api"
)

// 包名到包对象的映射
var structMap = map[string]func() interface{}{
	"template/api": func() interface{} { return &api.User{} },   // 调用User结构体的方法
}

反射核心代码

go 复制代码
package reflectcommon

import (
	"fmt"
	"reflect"
	api "template/api"
)

/*
args []interface{},支持任意类型的参数
*/
func CallPackageStructMethod(pkgPath, methodName string, args []interface{}) ([]reflect.Value, *[]error) {
	fmt.Println(123123)
	errs := []error{}

	// 1. 获取构造函数
	constructor, ok := structMap[pkgPath]
	if !ok {
		errs = append(errs, fmt.Errorf("包 %s 未注册", pkgPath))
		return nil, &errs
	}

	// 2. 创建实例
	instance := constructor()
	instanceValue := reflect.ValueOf(instance)

	// 3. 检查是否为指针
	if instanceValue.Kind() != reflect.Ptr {
		errs = append(errs, fmt.Errorf("构造函数必须返回指针"))
		return nil, &errs
	}

	// 4. 获取指向的结构体值
	structValue := instanceValue.Elem()
	if structValue.Kind() != reflect.Struct {
		errs = append(errs, fmt.Errorf("预期结构体,实际得到 %s", structValue.Kind()))
		return nil, &errs
	}
	
	// 5. 获取方法
	method := instanceValue.MethodByName(methodName)
	if !method.IsValid() {
		errs = append(errs, fmt.Errorf("方法 %s 不存在", methodName))
		return nil, &errs
	}

	// 6. 准备参数
	var in []reflect.Value
	for _, arg := range args {
		in = append(in, reflect.ValueOf(arg))
	}

	// 7. 调用方法并返回结果
	results := method.Call(in)
	return results, nil
}

定义结构体方法

template/api/create_token.go

go 复制代码
package api

import (
	"fmt"
	"template/common"
	"template/types"
)

type User struct {
	UserId string
	Token  string
}

func newCreateTokenApiV1() *types.Api {
	apiV1 := types.Api{
		Host:        "",
		Prefix:      "",
		Version:     "/v1",
		Url:         "/token/create",
		Method:      "POST",
		ContentType: "application/json",
	}
	return &apiV1
}


func (user User) CreateTokenApi(user1 map[string]interface{}, userId, token string) (*types.Api, *types.Result, error) {
	// 处理请求URL
	data := map[string]interface{}{
		"userId": userId,
		"token":  token,
		"user":   user1,
	}
	fmt.Println("xxxxxxx---进来啦")
	apiV1 := newCreateTokenApiV1()
	apiV1.ReqData = data

	result := &types.Result{
		Header:   nil,
		Duration: 2,
		Resp: struct {
			Code      string      `json:"code"`
			Message   string      `json:"message"`
			RequestId string      `json:"requestId"`
			Response  interface{} `json:"response"`
		}{
			Code:      "000000",
			Message:   "success",
			RequestId: "123456",
			Response:  data,
		},
	}
	return apiV1, result, nil
}

调用

go 复制代码
package main

import (
	"template/common"
	reflectcommon "template/reflectCommon"
	"template/types"

	"github.com/douyu/jupiter/pkg/xlog"
)

func main() {
	// 这里的顺序主要要与调用发放的入参保持一致
	reqData := []interface{}{
		map[string]interface{}{"id": 1, "name": "test", "age": 18},
		"MyUserid",
		"MuToken",
	} }}
	results, errList := reflectcommon.CallPackageStructMethod("template/api", "CreateTokenApi", reqData)
	if errList != nil && len(*errList) > 0 {
		xlog.Error("CreateTokenApi failed", xlog.Any("error", errList))
		return
	}

	// 5. 解析返回结果 (api, result, error)
	if len(results) >= 3 {
		apiV1 := results[0].Interface().(*types.Api)
		result := results[1].Interface().(*types.Result)
		err := results[2].Interface() // 可能是nil

		xlog.Info("success",
			xlog.Any("api", apiV1),
			xlog.Any("result", result),
			xlog.Any("error", err))
	}

}

执行日志:

PS D:\project\go\src\template> go run .

123123

xxxxxxx---进来啦

1746258031 INFO default success {"api": {"name":"","prefix":"/efile","version":"/v1","url":"/token/create","fullUrl":"","method":"POST","reqHeader":null,"ContentType":"application/json","param":null,"reqData":{"token":"MuToken","user":{"age":18,"id":1,"name":"test"},"userId":"MyUserid"},"excuteUid":"","respContentType":""}, "result": {"header":null,"duration":2,"resp":{"code":"000000","message":"success","requestId":"123456","response":{"token":"MuToken","user":{"age":18,"id":1,"name":"test"},"userId":"MyUserid"}}}, "error": null}

相关推荐
geovindu7 分钟前
python: Memento Pattern
开发语言·python·设计模式·备忘录模式
学无止境_永不停歇13 分钟前
十、C++多态
开发语言·c++
寻星探路30 分钟前
【JVM 终极通关指南】万字长文从底层到实战全维度深度拆解 Java 虚拟机
java·开发语言·jvm·人工智能·python·算法·ai
Aric_Jones34 分钟前
JavaScript 从入门到精通:完整语法指南
开发语言·javascript·ecmascript
岱宗夫up40 分钟前
FastAPI入门(上篇):快速构建高性能Python Web API
开发语言·前端·python·fastapi
Dxy12393102161 小时前
中文乱码恢复方案
开发语言·python
浅念-1 小时前
C/C++内存管理
c语言·开发语言·c++·经验分享·笔记·学习
回敲代码的猴子1 小时前
2月8日上机
开发语言·c++·算法
rongyili882 小时前
Dify 外部知识库集成 Milvus 实战指南
开发语言·python·milvus
IT猿手2 小时前
MOEA/D(基于分解的多目标进化算法)求解46个多目标函数及一个工程应用,包含四种评价指标,MATLAB代码
开发语言·算法·matlab·多目标算法