Writing more concise code in go

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

Writing more concise code in go

问题

我正在编写一个包,其中包含从XML-RPC服务器读取数据并将其存储在Go结构体数组中的函数。这里是一个片段,只涉及两种结构体:http://play.golang.org/p/a1dVA0UCzS。对于每种类型的结构体,我都有一个单独的“转换”函数。总共有超过20个这样的函数,它们只是彼此的简单副本,只是结构体名称不同。

有没有一种优雅的解决方案,而不是愚蠢地复制/粘贴相同的代码?

英文:

I'm writing a package with functions which read data from XML-RPC server and store it in arrays of go structs. Here is the snippet just for two kinds of structs: http://play.golang.org/p/a1dVA0UCzS. For each type of struct I have a separate "conversion" function. There are more than 20 of them in total - just plain copies of each other with just struct names replaced.

Is there an elegant solution instead of stupid copy/paste of the same code?

答案1

得分: 2

你可以使用反射来实现这个功能。请参考pkg/reflect文档。

对于你的情况,reflect.MakeFunc是一个有趣的函数。你可以使用反射来创建函数,然后发送消息并知道它们将接收的类型。以下是一个示例用法:

var getFooRequest func() []Foo                      // 请求的原型。
buildRequest("FooStore.GetFoo", &getFooRequest)     // 构建请求函数。

result := getFooRequest()                           // 实际发送请求。

这是一个可工作的示例(play):

func makeRequestFunc(req string, fptr interface{}) {
    baseRequestFunc := func(params []reflect.Value) []reflect.Value {
        log.Println("发送", req)
        return []reflect.Value{ reflect.ValueOf([]int{1,2,3,4}) }
    }

    fn := reflect.ValueOf(fptr).Elem()
    reqFun := reflect.MakeFunc(fn.Type(), baseRequestFunc)
    fn.Set(reqFun)
}

var fooRequest func() []int

makeRequestFunc("foo", &fooRequest)

log.Println(fooRequest())

在这个示例中,baseRequestFunc是你调用store.client.Call的地方,你可以使用任何你喜欢的字符串。从这个基本函数中,你可以创建一个可通过reflect.MakeFunc调用的新函数,并将结果存储在传递的函数指针中。

由于fooRequest具有明确的签名,不需要进行值解包。

英文:

You can do this by using reflection. See the pkg/reflect documentation.

For your case reflect.MakeFunc is interesting. You can create functions using reflection
which then send a message and know the types they will receive. Example usage:

var getFooRequest func() []Foo                      // Prototype of request.
buildRequest("FooStore.GetFoo", &getFooRequest)     // Build request function.

result := getFooRequest()                           // Actually sending.

A working example (play):

func makeRequestFunc(req string, fptr interface{}) {
	baseRequestFunc := func(params []reflect.Value) []reflect.Value {
		log.Println("Sending", req)
		return []reflect.Value{ reflect.ValueOf([]int{1,2,3,4}) }
	}

	fn := reflect.ValueOf(fptr).Elem()
	reqFun := reflect.MakeFunc(fn.Type(), baseRequestFunc)
	fn.Set(reqFun)
}

var fooRequest func() []int

makeRequestFunc("foo", &fooRequest)

log.Println( fooRequest() )

baseRequestFunc in this example is the place where you would call your store.client.Call
with whatever string you like. From this base function you create a new function that is
callable using reflect.MakeFunc and store the result in the passed function pointer.

As fooRequest has a definite signature, no value unpacking is needed.

huangapple
  • 本文由 发表于 2013年10月26日 03:05:13
  • 转载请务必保留本文链接:https://go.coder-hub.com/19597601.html
匿名

发表评论

匿名网友

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

确定