除了使用接口和扩展运算符之外,如何创建动态结构体?

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

How to create the dynamic struct except using interface and Using spread operator

问题

我正在尝试使用Go和Fiber框架创建新的API。我正在使用MongoDB。请参考下面的结构:

type Product struct {
    Name        string              `json:"name"`
    Code        string              `json:"code"`
    Description string              `json:"description"`
    Brand       string              `json:"brand"`
    Variants    []map[string]string `json:"variants"`
    Categories  []int               `json:"categories"`
}

Variants字段将包含另一个对象数组。但是字段是动态的,所以我无法定义结构。我使用了[]map[string]string来解决这个问题。

我的任务是按照以下格式生成CSV文件:

[{
    Name:        "Rock",
    Code:        "RRR",
    Description: "This is rock",
    Brand:       "R",
    ...variants
},
{
    Name:        "Rock",
    Code:        "RRR",
    Description: "This is rock",
    Brand:       "R",
    ...variants
},
{
    Name:        "Rambo",
    Code:        "RAM",
    Description: "This is Rambo",
    Brand:       "RA",
    ...variants
},
{
    Name:        "Rambo",
    Code:        "RAM",
    Description: "This is Rambo",
    Brand:       "RA",
    ...variants
}]

只有variants字段会在每一行中改变,其他字段保持不变。我已经创建了除了Variants之外的其他字段。我无法创建结构,因为数据是动态的。

我有很多困惑:

  1. 如何为动态字段创建结构?
  2. 如何将Variants展开到根级别?

我来自JavaScript背景,所以我们使用展开运算符。在这里,我对如何在Golang中实现这一点感到困惑。

帮帮我,朋友们!

英文:

I am trying to create the new API with Go and Fiber framework. I am using MongoDB.
Please refer to my below structure

type Product struct {
	Name           string              `json:"name"`
	Code           string              `json:"code"`
	Description    string              `json:"description"`
	Brand          string              `json:"brand"`
	Variants       []map[string]string `json:"variants"`
	Categories     []int               `json:"categories"`
}

The Variants field will have another set array of objects. But the fields will be dynamic. So I can't define the structure. Now this one I solved with []map[string][string].

My task here I have to form the CSV file with the below format.

[{
	Name: "Rock",
	Code: "RRR"
	Description: "This is rock"
	Brand: "R"
    ...variants
},
{
	Name: "Rock",
	Code: "RRR"
	Description: "This is rock"
	Brand: "R"
    ...variants
},
{
	Name: "Rambo",
	Code: "RAM"
	Description: "This is Rambo"
	Brand: "RA"
    ...variants
},
{
	Name: "Rambo",
	Code: "RAM"
	Description: "This is Rambo"
	Brand: "RA"
    ...variants
}]

Only variants will change for every row. Others will be remaining same
I formed the other fields except for the Variants. I can't create the struct because the data will be dynamic.

I have a lot of confusion

  1. How to create the struct for dynamic fields
  2. How to spread the Variants at the root level

I am from javascript. So, we used the spread operator. Here I am confused about how to do that in Golang.

Help me out, guys

答案1

得分: 2

@mkopriva是正确的

但是如果你愿意,你可以使用反射来动态构造一个新的结构体

以下是一个示例:

package main

import (
	"encoding/json"
	"fmt"
	"reflect"
)

type DynamicMap map[string]interface{}

type Product struct {
	Name        string            `json:"name"`
	Code        string            `json:"code"`
	Description string            `json:"description"`
	Brand       string            `json:"brand"`
	Variants    map[string]string `json:"variants"`
	Categories  []int             `json:"categories"`
}

func (j Product) MarshalJSON() ([]byte, error) {
	m := DynamicMap{}
	t := reflect.TypeOf(j)
	v := reflect.ValueOf(j)
	for i := 0; i < t.NumField(); i++ {
		if t.Field(i).Tag.Get("json") == "variants" {
			dyn := v.Field(i).Interface().(map[string]string)
			for key, val := range dyn {
				m[key] = val
			}
		} else if t.Field(i).Type.Kind() == reflect.String {
			m[t.Field(i).Tag.Get("json")] = v.Field(i).String()
		} else {
			m[t.Field(i).Tag.Get("json")] = v.Field(i)
		}

	}
	return json.Marshal(m)
}

func (j Product) UnmarshalJSON(data []byte) error {
	fmt.Println("Unmarshal...")
	return json.Unmarshal(data, &j)
}

func main() {
	p := Product{Name: "aa", Variants: map[string]string{"a": "a", "b": "b"}}
	marshal, err := json.Marshal(p)
	if err != nil {
		fmt.Printf("%v\n", err)
	}
	fmt.Printf("%s\n", marshal)
}

{"a":"a","b":"b","brand":"","categories":{},"code":"","description":"","name":"aa"}

英文:

@mkopriva is right
>However you can use reflection to dynamically construct a new struct if you like

follow is a example:

package main
import (
&quot;encoding/json&quot;
&quot;fmt&quot;
&quot;reflect&quot;
)
type DynamicMap map[string]interface{}
type Product struct {
Name        string            `json:&quot;name&quot;`
Code        string            `json:&quot;code&quot;`
Description string            `json:&quot;description&quot;`
Brand       string            `json:&quot;brand&quot;`
Variants    map[string]string `json:&quot;variants&quot;`
Categories  []int             `json:&quot;categories&quot;`
}
func (j Product) MarshalJSON() ([]byte, error) {
m := DynamicMap{}
t := reflect.TypeOf(j)
v := reflect.ValueOf(j)
for i := 0; i &lt; t.NumField(); i++ {
if t.Field(i).Tag.Get(&quot;json&quot;) == &quot;variants&quot; {
dyn := v.Field(i).Interface().(map[string]string)
for key, val := range dyn {
m[key] = val
}
} else if t.Field(i).Type.Kind() == reflect.String {
m[t.Field(i).Tag.Get(&quot;json&quot;)] = v.Field(i).String()
} else {
m[t.Field(i).Tag.Get(&quot;json&quot;)] = v.Field(i)
}
}
return json.Marshal(m)
}
func (j Product) UnmarshalJSON(data []byte) error {
fmt.Println(&quot;Unmarshal...&quot;)
return json.Unmarshal(data, &amp;j)
}
func main() {
p := Product{Name: &quot;aa&quot;, Variants: map[string]string{&quot;a&quot;: &quot;a&quot;, &quot;b&quot;: &quot;b&quot;}}
marshal, err := json.Marshal(p)
if err != nil {
fmt.Printf(&quot;%v\n&quot;, err)
}
fmt.Printf(&quot;%s\n&quot;, marshal)
}

{&quot;a&quot;:&quot;a&quot;,&quot;b&quot;:&quot;b&quot;,&quot;brand&quot;:&quot;&quot;,&quot;categories&quot;:{},&quot;code&quot;:&quot;&quot;,&quot;description&quot;:&quot;&quot;,&quot;name&quot;:&quot;aa&quot;}

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

发表评论

匿名网友

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

确定