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}

相关推荐
浪子明X10 小时前
十六位账本怎样发现传输差错:Internet Checksum 生活类比
开发语言
xiangyun6113 小时前
【408数据结构 08】队列:循环队列判空判满,408年年考,一次讲清
c语言·开发语言·数据结构·c++·算法
xiangyun6113 小时前
【408数据结构 06】双链表、循环链表、静态链表
c语言·开发语言·数据结构·c++·算法
白远山14 小时前
家政服务家政社区派单实战:调度系统架构设计与实现指南
java·开发语言·小程序·架构·需求分析
DevRay15 小时前
Java 21虚拟线程深度实战:告别线程池焦虑,百万并发吞吐量直接翻倍(原理+代码+避坑)
java·开发语言
free-elcmacom15 小时前
C++学习<1>程序分区
开发语言·c++
醉颜凉15 小时前
Java 必看:如何彻底避免 HashMap 多线程死循环问题?
java·开发语言
默 语15 小时前
Java新手入门:从零开始安装JDK并配置环境变量
java·开发语言·python·mysql·group by·1024程序员节·数据去重
Brilliantwxx16 小时前
【STM32】 I2C_EEPROM_test 工程(实战篇)
开发语言·stm32·单片机·嵌入式硬件·ecmascript
清水白石00816 小时前
Python 异步编程深度解析:Cancellation 到底是异常还是控制信号?从 asyncio 取消机制到企业级事务设计最佳实践
开发语言·python