extending structs with (relatively) unknown/arbitrary methods, go reflection(or avoiding reflection)

huangapple go评论81阅读模式
英文:

extending structs with (relatively) unknown/arbitrary methods, go reflection(or avoiding reflection)

问题

下面显然不起作用:

Arbitrary := struct {
    field1 string
    field2 string
}{"a", "b"}

fmap := make(map[string]func(string) string)
fmap["fone"] = func(s string) string { fmt.Printf("function fone: %s", s) }
fmap["ftwo"] = func(s string) string { fmt.Printf("function ftwo: %s", s) }

// 可能可以,作为简单的示例,到这一点需要使用反射
// 下面不起作用
Arbitrary.fone = fmap["fone"]

Arbitrary.fone("hello")

上述代码是我尝试做的核心部分:创建一个带有值的结构体,然后从函数映射或传入的函数创建结构体的方法。基本上,我有一个带有数据和不确定行为的结构体,需要通过在创建类型时扩展方法来扩展。

我正在寻找明显且不可避免的解决方案:

  1. 如何在Go中实现这一点。

  2. 为什么不应该这样做,或者不能在Go中这样做(使用反射包是可能的,我只是还没有找到示例或进行深入推理)。

  3. 如何在Go中正确实现这一点(我还没有完全弄清楚某种接口构造。我尝试过一个可以处理行为的接口,但它不能考虑到可能添加的其他行为,至少我还没有完全弄清楚接口的使用,这是问题的一部分)。

如果你需要复杂性,这里是我尝试完成的实际任务的开始部分,使结构体的行为可扩展。

英文:

The below does not work obviously:

Arbitrary := struct {
	field1 string
	field2 string
}{"a", "b"}

fmap := make(map[string]func(string) string)
fmap["fone"] = func(s string) string { fmt.Printf("function fone: %s", s) }
fmap["ftwo"] = func(s string) string { fmt.Printf("function ftwo: %s", s) }

// probably ok, as simple examples go, to this point where reflection needs to be used
// the below does not work 
Arbitrary.fone = fmap["fone"]

Arbitrary.fone("hello")

The above is the core of what I'm trying to do: create a struct with values, and then create methods on the struct from a map of functions, or functions passed in. Basically I have a structure with data & ambiguous behavior that needs to be extended with methods unknown until creating the type.

I'm looking for the obvious & inevitable:

  1. How to do this in Go

  2. Why this shouldn't be done, or can't be done in Go (its possible with the reflect package, I just haven't found examples or reasoned thorough it yet)

  3. How this should be done in Go (some sort of interface construct I've not figured out wholly. I've tried an interface which can handle the behavior; but it doesn't account for other behaviors that might be added, at the least I haven't figured out interface usage fully yet which is part of the issue)

If you're a person needing complexity here is the start of the actual task I'm trying to accomplish, making that structs behavior extendable.

答案1

得分: 1

我完全误解了这个问题。

不,你不能凭空创建一个新的结构体并给它赋值,即使你可以,也请不要这样做。

你可以使用多个接口,例如:

type Base interface {
    Id() int //所有结构体都必须实现这个方法
}
type Foo interface {
    Base
    Foo()
}
type Bar interface {
    Base
    Bar()
}

然后创建一个 map[string]Base,稍后可以对值进行断言。

//将原始答案作为解决问题的另一种方法。

<strike>通常情况下,这种操作使用反射来完成,但如果你只有有限数量的接受的“回调函数”,你可以使用类型断言和 interface{} map,省去了使用反射的需要。</strike>

var ctx = &Ctx{"Hello"}
var funcs = map[string]interface{}{
    "m3": ctx.Do,
    "m4": func(c *Ctx) { fmt.Println("ctx:", c) },
}

type Ctx struct {
    Name string
}

func (c *Ctx) Do() {
    fmt.Printf("Do: %+v\n", c)
}

func call(m string) {
    if f, ok := funcs[m]; ok {
        switch fn := f.(type) {
        case func():
            fn()
        case func(*Ctx):
            fn(&Ctx{"Hello world"})
        default:
            panic(fn)
        }
    }
}

<kbd>playground</kbd>

英文:

I completely misunderstood the question.

NO, you can't create a new struct out of thin air and assign fields to it, also even if you could, for the love of everything that's holy, don't do that.

You can use multiple interfaces for example:

type Base interface {
	Id() int //all structs must implement this
}
type Foo interface {
	Base
	Foo()
}
type Bar interface {
	Base
	Bar()
}

then make a map[string]Base, and you can assert the value later.

//leaving the original answer as a different approach to the problem.

<strike>While usually that kind of stuff is done using reflection, if you have a limited number of accepted "callbacks" you can use type assertion and an interface{} map, dropping the need for reflection.</strike>

var ctx = &amp;Ctx{&quot;Hello&quot;}
var funcs = map[string]interface{}{
	&quot;m3&quot;: ctx.Do,
	&quot;m4&quot;: func(c *Ctx) { fmt.Println(&quot;ctx:&quot;, c) },
}

type Ctx struct {
	Name string
}

func (c *Ctx) Do() {
	fmt.Printf(&quot;Do: %+v\n&quot;, c)
}

func call(m string) {
	if f, ok := funcs[m]; ok {
		switch fn := f.(type) {
		case func():
			fn()
		case func(*Ctx):
			fn(&amp;Ctx{&quot;Hello world&quot;})
		default:
			panic(fn)
		}
	}
}

<kbd>playground</kbd>

huangapple
  • 本文由 发表于 2014年8月28日 21:03:50
  • 转载请务必保留本文链接:https://go.coder-hub.com/25549520.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定