如何定义一个泛型类型,可以容纳多种不同的类型?

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

How to define a generic types that will hold many other diferent types

问题

问题背景:

我们正在使用golang在AWS中创建一个lambda函数,在这个函数中,我们需要使用GraphQL从数据库中检索一些信息。

我们已经能够做到这一点,但是当将响应解析为有效类型时,我们目前遇到了一些问题,因为我们希望使用单个类型来保存所有可能的情况。

为了更好地解释这一点,请查看“示例”,然后查看“目标”。

示例:

我们将收到类似于以下内容的内容:

{
  "data": {
    "getUser": {
      "id": "example1",
      "name": "example_name"
    }
  }
}

以及类似于以下内容的内容(以及更多):

{
  "data": {
    "getEvent": {
        "id": "event1",
        "name": "example_name"
      }
    }
  }
}

目标:

因此,我们想要创建一个表示“data”字段的类型,并且它还可以具有多个表示形式,如下所示:

type Response {
  Data <???> `json:"data"`
}

其中是一个可以同时是“getUser”和“getEvent”(以及许多其他不同类型)的类型:

type GetPerson {
  Id string `json:"id"`
  Name string `json:"name"`
}

type GetEvent {
  Id string `json:"id"`
  Name string `json:"name"`
}

附注:我们对于更好地解决这个问题的不同建议持开放态度,如果需要,我们还可以添加更多信息。

英文:

Some context to the problem:

We are creating a lambda function in aws with golang and in this function we need to retrieve some information from our database using graphql.

We were able to do so but we are currently facing some issues when parsing the response into a valid type because we wanted to use a single type to hold all possible scenarios.

To better explain this, look into "Examples" and then see the "Goal".

Examples:

We will be receiving something like this:

{
  &quot;data&quot;: {
    &quot;getUser&quot;: {
      &quot;id&quot;: &quot;example1&quot;,
      &quot;name&quot;: &quot;example_name&quot;
    }
  }
}

and like this (and many more):

{
  &quot;data&quot;: {
    &quot;getEvent&quot;: {
        &quot;id&quot;: &quot;event1&quot;,
        &quot;name&quot;: &quot;example_name&quot;
      }
    }
  }
}

Goal:

So, what we wanted to create was a type that represented the "data" field and that it could also have multiple representations, like this:

type Response {
  Data &lt;???&gt; `json:&quot;data&quot;`
}

Where the <???> is a type that can be, at the same type, a "getUser" and a "getEvent" (and many more different types):

type GetPerson {
  Id string `json:&quot;id&quot;`
  Name string `json:&quot;name&quot;`
}

type GetEvent {
  Id string `json:&quot;id&quot;`
  Name string `json:&quot;name&quot;`
}

P.S: We are open to different suggestions as to better approach this issue and if needed, we can also add more information.

答案1

得分: 3

你可以使用一个fat interface(胖接口):

type Data struct {
   Person *GetPerson `json:"user"`
   Event *GetEvent `json:"event"`
   ...
}

然后,解析一个Data的实例,查看其中一个包含的元素不是nil,然后使用它。

你也可以实现一个多态接口。下面是这个想法的草图:

type Data struct {
  Item interface{}
}

type dataMarshal struct {
   Item map[string]json.RawMessage
}

// 将 JSON 键映射到工厂函数
var factory = map[string]func() interface{} {
   "user": func() interface{} { return &GetUser{} },
   "event": func() interface{} { return &GetEvent{} },
}

func (d *Data) UnmarshalJSON(in []byte) error {
  var data dataMarshal
  // 解析带有键和原始消息的数据
  err := json.Unmarshal(in, &data)
  for k, v := range data.Item {
     // 根据键创建一个新对象
     obj := factory[k]()
     // 解析新对象
     err := json.Unmarshal(v, obj)
     d.Item = obj
  }
  return nil
}

注意:以上代码是用Go语言编写的。

英文:

You can use a fat interface:

type Data struct {
   Person *GetPerson `json:&quot;user&quot;`
   Event *GetEvent `json:&quot;event&quot;`
   ...
}

Then, unmarshal an instance of Data, see which one of the included elements is not nil, and use that.

You can also implement a polymorphic interface. Below is the sketch of the idea:

type Data struct {
  Item interface{}
}

type dataMarshal struct {
   Item map[string]json.RawMessage
}

// Map JSON keys to factory functions
var factory:=map[string]func()interface{} {
   &quot;user&quot;: func() interface{} { return &amp;GetUser{} },
   &quot;event&quot;: func() interface{} {return &amp;GetEvent{} },
}

func (d *Data) UnmarshalJSON(in []byte) error {
  var data dataMarshal
  // Unmarshal data with key and raw message
  err:=json.Unmarshal(in,&amp;data)
  for k,v:=range data.Item {
     // Based on the key, create a new object
     obj:=factory[k]()
      // Unmarshal new object
     err:=json.Unmarshal(v,obj)
     d.Item=obj
  }
  return nil
}

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

发表评论

匿名网友

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

确定