Passing a struct Type in Golang?

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

Passing a struct Type in Golang?

问题

请原谅我的问题,我对Golang还不熟悉,可能采用了错误的方法。

我目前正在为一个内部服务实现一个Terraform提供程序。

正如预期的那样,这需要将JSON数据解组为预定义的结构类型,例如:

type SomeTypeIveDefined struct {
	ID   string `json:"id"`
	Name string `json:"name"`
}

我陷入了这样一种情况,我有很多重复的代码,看起来像这样:

	res := r.(*http.Response)
	var tempThing SomeTypeIveDefined
	dec := json.NewDecoder(res.Body)
	err := dec.Decode(&tempThing)

为了减少重复,我决定创建一个函数来执行JSON解组,但将结构类型作为参数传入。

我在StackOverflow文章和Google Groups中搜索了很多,试图理解一些关于使用reflect包的答案,但在使用它方面并没有取得太大的成功。

我最新的尝试是使用reflect.StructOf并传入一组StructField,但这仍然需要使用myReflectedStruct.Field(0)而不是myReflectedStruct.ID

我怀疑在Golang中可能没有办法实现这一点,直到类似泛型的东西在Golang中广泛可用。

我考虑过为结构体创建一个接口,要求实现一个解组方法,然后我可以将接口传递给函数并调用解组方法。但是,我仍然需要在所有结构体上实现解组。

我只是想知道有什么建议可以实现我想要的效果,请问有什么建议吗?

英文:

Please forgive my question, I'm new to Golang and possibly have the wrong approach.

I'm currently implementing a Terraform provider for an internal service.

As probably expected, that requires unmarshalling JSON data in to pre-defined Struct Types, e.g:

type SomeTypeIveDefined struct {
	ID   string `json:"id"`
	Name String `json:"name"`
}

I've got myself in to a situation where I have a lot of duplicate code that looks like this

	res := r.(*http.Response)
	var tempThing SomeTypeIveDefined
	dec := json.NewDecoder(res.Body)
	err := dec.Decode(&tempThing)

In an effort to reduce duplication, I decided what I wanted to do was create a function which does the JSON unmarshalling, but takes in the Struct Type as a parameter.

I've trawled through several StackOverflow articles and Google Groups trying to make sense of some of the answers around using the reflect package, but I've not had much success in using it.

My latest attempt was using reflect.StructOf and passing in a set of StructFields, but that still seems to require using myReflectedStruct.Field(0) rather than myReflectedStruct.ID.

I suspect there may be no way until something like Generics are widely available in Golang.

I considered perhaps an interface for the structs which requires implementing an unmarshal method, then I could pass the interface to the function and call the unmarshal method. But then I'm still implementing unmarshal on all the structs anyway.

I'm just wondering what suggestions there may be for achieving what I'm after, please?

答案1

得分: 4

创建一个带有重复代码的辅助函数。将目标值作为指针传递。

func decode(r *http.Response, v interface{}) error {
    return json.NewDecoder(res.Body).Decode(v)
}

使用指向你的对象的指针调用辅助函数:

var tempThing SomeTypeIveDefined
err := decode(r, &tempThing)
英文:

Create a helper function with the repeated code. Pass the destination value as a pointer.

func decode(r *http.Repsonse, v interface{}) error {
     return json.NewDecoder(res.Body).Decode(v)
}

Call the helper function with a pointer to your thing:

var tempThing SomeTypeIveDefined
err := deocde(r, &tempThing)

答案2

得分: 1

你可以使用接口来实现这个功能:

func decodeResponse(r *http.Response, dest interface{}) error {
    dec := json.NewDecoder(r.Body)
    return dec.Decode(dest)
}

func handler(...) {
    res := r.(*http.Response)
    var tempThing SomeTypeIveDefined
    if err := decodeResponse(res, &tempThing); err != nil {
        // 处理错误
    }
    ...
}

你不需要为结构体实现解析方法,因为标准库的解码器会使用反射来设置结构体字段。

英文:

You can do this with interfaces:

func decodeResponse(r *http.Response, dest interface{}) error {
    dec := json.NewDecoder(r.Body)
    return dec.Decode(dest)
}

func handler(...) {
    res := r.(*http.Response)
    var tempThing SomeTypeIveDefined
    if err:=decodeResponse(res,&tempThing); err!=nil {
      // handle err
    }
   ...
}

You don't need to implement an unmarshal for the structs, because the stdlib decoder will use reflection to set the struct fields.

huangapple
  • 本文由 发表于 2022年1月2日 10:48:37
  • 转载请务必保留本文链接:https://go.coder-hub.com/70553294.html
匿名

发表评论

匿名网友

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

确定