如何将 map[string]interface{} 数据转换为结构体(struct)?

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

how to convert map[string]interface{} data to struct

问题

我不知道如何提问,所以我将用一个例子来提问。

我有一些数据,如下所示:

  1. {
  2. ..
  3. "velocityStatEntries": {
  4. "8753": {
  5. "estimated": {"value": 23.0,"text": "23.0"},
  6. "completed": {"value": 27.0,"text": "27.0"}
  7. },
  8. "8673": {
  9. "estimated": {"value": 54.5,"text": "54.5"},
  10. "completed": {"value": 58.5,"text": "58.5"}
  11. },
  12. .
  13. .
  14. .
  15. }
  16. ..
  17. }

我想声明一个类型,将映射键值作为它的"KEY"或我指定的任何属性。是否可以在不使用映射迭代的情况下实现?

期望的输出:

  1. {...
  2. "velocityStatEntries": {
  3. {
  4. "key": "8753",
  5. "estimated": {"value": 54.5,"text": "54.5"},
  6. "completed": {"value": 58.5,"text": "58.5"}
  7. },
  8. {
  9. "key": "8673",
  10. "estimated": {"value": 54.5,"text": "54.5"},
  11. "completed": {"value": 58.5,"text": "58.5"}
  12. },
  13. }
  14. ...
  15. }

这是我所做的:

  1. type VelocityStatEntry struct {
  2. Key string
  3. Estimated struct {
  4. Value float64 `json:"value"`
  5. Text string `json:"text"`
  6. } `json:"estimated"`
  7. Completed struct {
  8. Value float64 `json:"value"`
  9. Text string `json:"text"`
  10. } `json:"completed"`
  11. }
  12. type RapidChartResponse struct {
  13. ...
  14. VelocityStatEntries map[string]VelocityStatEntry `json:"velocityStatEntries"`
  15. ..
  16. }

但它不起作用。我想将字符串映射键值作为KEY属性。

英文:

I do not know how to ask, so i will ask with an example.

I have some data like that

  1. {
  2. ..
  3. "velocityStatEntries": {
  4. "8753": {
  5. "estimated": {"value": 23.0,"text": "23.0"},
  6. "completed": {"value": 27.0,"text": "27.0"}
  7. },
  8. "8673": {
  9. "estimated": {"value": 54.5,"text": "54.5"},
  10. "completed": {"value": 58.5,"text": "58.5"}
  11. },
  12. .
  13. .
  14. .
  15. }
  16. ..
  17. }

I want to declare a type that takes map key to its "KEY" or any property that is given by me.
Is it possible without using map iteration?

Expected output:

  1. {...
  2. "velocityStatEntries": {
  3. {
  4. "key": "8753",
  5. "estimated": {"value": 54.5,"text": "54.5"},
  6. "completed": {"value": 58.5,"text": "58.5"}
  7. },
  8. {
  9. "key": "8673",
  10. "estimated": {"value": 54.5,"text": "54.5"},
  11. "completed": {"value": 58.5,"text": "58.5"}
  12. },
  13. }
  14. ...
  15. }

This is what i have done

  1. type VelocityStatEntry struct {
  2. Key string
  3. Estimated struct {
  4. Value float64 `json:"value"`
  5. Text string `json:"text"`
  6. } `json:"estimated"`
  7. Completed struct {
  8. Value float64 `json:"value"`
  9. Text string `json:"text"`
  10. } `json:"completed"`
  11. }
  12. type RapidChartResponse struct {
  13. ...
  14. VelocityStatEntries map[string]VelocityStatEntry `json:"velocityStatEntries"`
  15. ..
  16. }

But it is not working. I want to take that string map key to KEY property.

答案1

得分: 3

如果数据源是JSON格式的,那么你应该跳过map[string]interface{},而是使用你所需的自定义解组器(custom unmarshaler)来实现你想要的功能。可以考虑使用map[string]json.RawMessage。但是,如果可能的话,尽量避免使用map[string]interface{}转换为结构体,因为这样做会很麻烦。

例如:

  1. type VelocityStatEntryList []*VelocityStatEntry
  2. func (ls *VelocityStatEntryList) UnmarshalJSON(data []byte) error {
  3. var m map[string]json.RawMessage
  4. if err := json.Unmarshal(data, &m); err != nil {
  5. return err
  6. }
  7. for k, v := range m {
  8. e := &VelocityStatEntry{Key: k}
  9. if err := json.Unmarshal([]byte(v), e); err != nil {
  10. return err
  11. }
  12. *ls = append(*ls, e)
  13. }
  14. return nil
  15. }

https://go.dev/play/p/VcaW_BWXRVr

英文:

If the data originates from JSON then you should skip the map[string]interface{} and instead use a custom unmarshaler implemented by your desired struct that does what you want. Perhaps by utilizing a map[string]json.RawMessage. But map[string]interface{} to struct conversion is a pain, avoid it if possible.

For example:

  1. type VelocityStatEntryList []*VelocityStatEntry
  2. func (ls *VelocityStatEntryList) UnmarshalJSON(data []byte) error {
  3. var m map[string]json.RawMessage
  4. if err := json.Unmarshal(data, &m); err != nil {
  5. return err
  6. }
  7. for k, v := range m {
  8. e := &VelocityStatEntry{Key: k}
  9. if err := json.Unmarshal([]byte(v), e); err != nil {
  10. return err
  11. }
  12. *ls = append(*ls, e)
  13. }
  14. return nil
  15. }

https://go.dev/play/p/VcaW_BWXRVr

huangapple
  • 本文由 发表于 2022年1月7日 21:29:23
  • 转载请务必保留本文链接:https://go.coder-hub.com/70621975.html
匿名

发表评论

匿名网友

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

确定