You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Go的reflect.MakeFunc实现可配置时机的函数装饰?

基于Go Reflect实现可配置执行时机的函数装饰器

要实现支持前置/后置注入逻辑的装饰器,需要调整现有代码结构,让Decorate能接收执行时机和自定义处理函数,同时让Handle具备处理原函数参数、返回值的能力。以下是完整实现:

核心调整点

  • 定义执行时机枚举,明确区分前置/后置逻辑
  • 重构处理函数的签名,使其能接收原函数参数、原返回值,并输出修改后的结果
  • 扩展Decorate函数,接收时机配置和处理函数,动态生成装饰后的函数

完整代码

package main

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

// 定义执行时机枚举
type ExecuteTiming int

const (
	Before ExecuteTiming = iota // 前置执行:先运行处理逻辑,再决定是否执行原函数
	After                       // 后置执行:先运行原函数,再用处理逻辑修改返回结果
)

// 定义处理函数的统一类型,兼容原函数的参数和返回值处理
type HandleFunc func(args []reflect.Value, originalResults []reflect.Value) []reflect.Value

func main() {
	func1 := OriginFunc

	// 示例1:前置注入错误,直接返回错误不执行原函数
	Decorate(&func1, Before, func(args []reflect.Value, originalResults []reflect.Value) []reflect.Value {
		// 构造符合原函数返回类型的结果:int返回0,error返回自定义错误
		return []reflect.Value{
			reflect.ValueOf(0),
			reflect.ValueOf(errors.New("前置注入错误")),
		}
	})
	val, err := func1(1, 2)
	fmt.Printf("前置注入结果:val=%d, err=%v\n", val, err)

	// 重置原函数,测试后置注入
	func1 = OriginFunc
	Decorate(&func1, After, func(args []reflect.Value, originalResults []reflect.Value) []reflect.Value {
		// 保留原函数的计算结果,替换error为自定义错误
		return []reflect.Value{
			originalResults[0],
			reflect.ValueOf(errors.New("后置注入错误")),
		}
	})
	val, err = func1(1, 2)
	fmt.Printf("后置注入结果:val=%d, err=%v\n", val, err)
}

func OriginFunc(a, b int) (int, error) {
	return a + b, nil
}

// Decorate 扩展为可配置执行时机和处理函数的装饰器
func Decorate(fn interface{}, timing ExecuteTiming, handle HandleFunc) {
	v := reflect.ValueOf(fn).Elem()
	originalFn := v

	m := reflect.MakeFunc(v.Type(), func(args []reflect.Value) []reflect.Value {
		switch timing {
		case Before:
			// 前置逻辑:直接调用处理函数,返回其生成的结果(原函数不会执行)
			return handle(args, nil)
		case After:
			// 后置逻辑:先执行原函数获取结果,再传给处理函数修改
			originalResults := originalFn.Call(args)
			return handle(args, originalResults)
		default:
			// 默认直接执行原函数
			return originalFn.Call(args)
		}
	})

	v.Set(m)
}

代码说明

  1. ExecuteTiming枚举:用常量明确两种执行时机,避免硬编码带来的维护问题
  2. HandleFunc类型:统一处理函数的签名,确保能适配不同原函数的参数和返回值结构
  3. Decorate函数扩展:通过reflect动态生成新函数,根据传入的时机参数控制执行顺序
  4. 示例场景:
    • 前置注入:直接返回自定义错误,原函数逻辑不会触发
    • 后置注入:保留原函数的业务计算结果,仅修改返回的错误信息

内容的提问来源于stack exchange,提问作者Pkzzz

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.14 19:00:30