【发布时间】: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