【问题标题】:How to get an arbitrary method signature using reflection?如何使用反射获得任意方法签名?
【发布时间】:2022-09-29 05:50:27
【问题描述】:

我可以多用一双眼睛来解决这个挑战,playground here

最终目标是将函数和结构公共函数注册到活动管理器中,并通过函数名执行它们,因此类似于:

   pool := map[string]interface{
       \"Sample\": func(ctx context.Context) error,
       \"Sample2\": func(ctx context.Context, args ...interface{}) error,
       \"SampleFromStruct\": func(ctx context.Context) error,
       \"Sample2FromStruct\": func(ctx context.Context, args ...interface{}) error,
   }

功能看起来像:

func Sample(ctx context.Context) error {
    fmt.Println(\"exec Sample\")
    return nil
}

func Sample2(ctx context.Context, args interface{}) error {
    arguments := struct {
        Foo string `json:\"foo\"`
        Bar string `json:\"bar\"`
    }{}

    b, err := json.Marshal(args)
    if err != nil {
        return err
    }

    if err := json.Unmarshal(b, &arguments); err != nil {
        return err
    }

    fmt.Println(\"exec Sample2 with args\", arguments)

    return nil
}

// and same but with struct
type ActivityInStruct struct {
    Bar string
}

func (a *ActivityInStruct) SampleInStruct(ctx context.Context) error {
    fmt.Println(\"Value of Bar\", a.Bar)
    return Sample(ctx)
}

func (a *ActivityInStruct) Sample2InStruct(ctx context.Context, args interface{}) error {
    fmt.Println(\"Value of Bar\", a.Bar)
    return Sample2(ctx, args)
}

说到这里,我让它使用具有以下实现的函数:

type activityManager struct {
    fnStorage map[string]interface{}
}

func (lm *activityManager) Register(fn interface{}) error {
    fnName := strings.Split((runtime.FuncForPC(reflect.ValueOf(fn).Pointer()).Name()), \".\")
    name := fnName[len(fnName)-1]
    lm.fnStorage[name] = fn
    return nil
}

func (lm *activityManager) Exec(ctx context.Context, fnName string, args ...interface{}) error {
    fn, ok := lm.fnStorage[fnName]
    if !ok {
        return fmt.Errorf(\"activity %s not found\", fnName)
    }

    if signatureCtx, ok := fn.(func(context.Context) error); ok {
        return signatureCtx(ctx)
    }

    if signatureWithArgument, ok := fn.(func(context.Context, interface{}) error); ok {
        return signatureWithArgument(ctx, args[0])
    }

    return fmt.Errorf(\"signature for %s not supported\", fnName)

}

所以执行看起来像这样:


func NewManager() *activityManager {
    return &activityManager{
        fnStorage: map[string]interface{}{},
    }
}

/*...*/
    ctx := context.Background()
    manager := NewManager()
    manager.Register(Sample)
    manager.Register(Sample2)

    if err := manager.Exec(ctx, \"Sample\"); err != nil {
        fmt.Println(\"Sample error\", err.Error())
        return
    }

    args1 := map[string]interface{}{
        \"foo\": \"isFoo\",
        \"bar\": \"isBar\",
    }
    if err := manager.Exec(ctx, \"Sample2\", args1); err != nil {
        fmt.Println(\"Sample2 error\", err.Error())
        return
    }

但是,要注册这样的内容:


func (lm *activityManager) RegisterStruct(fn interface{}) error {
    t := reflect.TypeOf(fn)
    for i := 0; i < t.NumMethod(); i++ {
        m := t.Method(i)
        if m.IsExported() {

            /*
                               This won\'t work cause m.Type are
                               func(*main.ActivityInStruct, context.Context, interface {}) error
                                           func(*main.ActivityInStruct, context.Context) error

                                          instead of
                                          func(context.Context, interface {}) error
                                          func(context.Context) error
            */

            lm.fnStorage[m.Name] = m.Func
        }
    }

    return nil
}



/* Register Activity from Public methods in struct */
    activitiesStruct := &ActivityInStruct{
        Bar: \"I\'m the Bar\",
    }

    manager.RegisterStruct(activitiesStruct)

我无法让它工作,因为反射显示了这样的方法签名,func(*main.ActivityInStruct, context.Context, interface {}) error

知道如何解决吗? the full playground is here

    标签: go reflection


    【解决方案1】:

    致电Value.Method 获取method value

    func (lm *activityManager) RegisterStruct(fn interface{}) error {
        v := reflect.ValueOf(fn)
        t := v.Type()
        for i := 0; i < t.NumMethod(); i++ {
            m := t.Method(i)
            if m.IsExported() {
                lm.fnStorage[m.Name] = v.Method(i).Interface()
            }
        }
        return nil
    }
    

    【讨论】:

    • 冠军!非常感谢你!这正是我需要的!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-11-10
    相关资源
    最近更新 更多