Golang通过反射动态调用包下面方法、动态调用结构体下方法,类似JS的eval

文章展示了如何在Golang中通过反射(reflect)包实现动态调用结构体的方法和注册函数,以便于在运行时执行未知的方法。`CallMethod`函数用于调用结构体的方法,而`RegisterFunction`和`Eval`则用于注册和执行全局函数。在示例代码中,`main`包中定义了`Add`函数和`MyStruct`结构体,动态调用这些方法和函数得到了预期的结果。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  1. Golang通过反射动态调用包下面方法 --> 需要先注册

  2. 动态调用结构体下方法

  3. 类似JS的eval

eval.go

package util

import (
	"errors"
	"fmt"
	"reflect"
)

// 调用结构体下方法
func CallMethod(instance interface{}, methodName string, args ...interface{}) ([]interface{}, error) {
	// 获取方法的反射值
	methodValue := reflect.ValueOf(instance).MethodByName(methodName)

	// 检查方法是否存在
	if !methodValue.IsValid() {
		return nil, fmt.Errorf("method not found: %s", methodName)
	}

	// 如果方法是通过指针接收者定义的,则获取指针类型的反射值
	if methodValue.Type().IsVariadic() {
		ptrValue := reflect.ValueOf(instance)
		methodValue = ptrValue.MethodByName(methodName)
	}

	// 构造方法的参数列表
	methodArgs := make([]reflect.Value, len(args))
	for i, arg := range args {
		methodArgs[i] = reflect.ValueOf(arg)
	}

	// 调用方法并获取返回值
	resultValues := methodValue.Call(methodArgs)

	// 如果方法没有返回值,则返回 nil
	if len(resultValues) == 0 {
		return nil, nil
	}

	// 将返回值转为 interface{} 类型并返回
	results := make([]interface{}, len(resultValues))
	for i, v := range resultValues {
		results[i] = v.Interface()
	}
	return results, nil
}

// 注册变量
var importedFunctions = make(map[string]map[string]interface{})

// 注册
func RegisterFunction(packageName, funcName string, function interface{}) {
	if importedFunctions[packageName] == nil {
		importedFunctions[packageName] = make(map[string]interface{})
	}
	importedFunctions[packageName][funcName] = function
}

// 调用包下面的方法
func Eval(packageName string, funcName string, args ...interface{}) ([]interface{}, error) {
	// Get the function's reflect.Value using the package path and function name
	funcValue := reflect.ValueOf(importedFunctions[packageName][funcName])

	// Check if the function exists
	if !funcValue.IsValid() {
		return nil, errors.New("Failed to find function: " + funcName)
	}

	// Construct the function's argument list
	funcArgs := make([]reflect.Value, len(args))
	for i, arg := range args {
		funcArgs[i] = reflect.ValueOf(arg)
	}

	// Call the function and get the return values
	resultValues := funcValue.Call(funcArgs)

	// Convert the return values to interface{} and save them in the result slice
	results := make([]interface{}, len(resultValues))
	for i, result := range resultValues {
		results[i] = result.Interface()
	}

	return results, nil
}

main.go

package main

import (
	"fmt"
	"reflect"
	"test/util"
)

type MyStruct struct{}

func (s MyStruct) Hello(name string) string {
	return "Hello, " + name + "!"
}

func (s *MyStruct) Add(a, b int) int {
	return a + b
}

func Add(a, b int) int {
	return a + b
}

func init() {
	// 注册
	util.RegisterFunction("main", "Add", Add)
}

func main() {
	// 通过包名和方法名动态调用
	packageName := "main"
	funcName := "Add"
	args := []interface{}{10, 20}
	results, err := util.Eval(packageName, funcName, args...)
	if err != nil {
		fmt.Println("Error:", err)
		return
	}
	sum := results[0].(int)
	fmt.Println("Result:", sum) // Output: Result: 30

	// 通过结构体动态调用地下方法
	instance := MyStruct{}

	// 调用 Hello 方法
	result1, _ := util.CallMethod(instance, "Hello", "John")
	fmt.Println(result1[0].(string)) // Output: Hello, John!

	// 调用 Add 方法
	args2 := []interface{}{10, 20}
	result2, _ := util.CallMethod(&instance, "Add", args2...)
	fmt.Println(result2[0].(int)) // Output: 30
}

运行截图

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值