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}

相关推荐
Cc.Y24 分钟前
Java零基础入门:字符串深度掌握——从基础API到StringBuilder性能优化
java·开发语言·性能优化
java资料站4 小时前
十一、评估测试
开发语言·人工智能·python
左手の明天5 小时前
SLIP 协议封装与解析详解:原理、C 代码与实战案例
linux·c语言·开发语言·c++
海上小飞龙5 小时前
【KMP算法-下篇】同一道题:Java 库函数 2600 微秒,手写 KMP 16 微秒
java·开发语言·算法
福大大架构师每日一题5 小时前
ollama v0.35.0发布:决策模型正式上线,接口直接返回选择、概率与评分
golang
朝朝辞暮i5 小时前
C++ 第 12 课:局部变量、作用域、变量生命周期
开发语言·c++·算法
狗凯之家源码网6 小时前
淘客口令落地页生成器 PHP 版深度评测
开发语言·php
画绛集美术6 小时前
本地化部署LLM用于美术史问答:一间美术教室的实践记录
开发语言·php
八解毒剂6 小时前
【计组】中央处理器CPU
java·开发语言·计算机组成原理