为什么在Golang中使用Json Unmarshall时会改变数组类型?

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

Why Json Unmarshall changing array type in Golang?

问题

我正在尝试以功能方式填充我的Postgres数据库。在我的情况下,SeedSchema()函数可以接受任何类型的结构体。因此,我定义了一个接口,并创建了用于填充结构体的函数。我尝试过使用泛型和不使用泛型。

当我将任何JSON数组作为字节数组从文件中解组时,json.Unmarshal方法会更改我的结构体的tempMember成员。例如,models.Term变为map[string]interface{}。在此函数之前,我已经使用了unmarshal,并没有遇到这种情况。

这是我的SeedSchema()函数:

func (db *Database) SeedSchema(models ...globals.Seeder[any]) error {
	var (
		subjects []globals.Seeder[any]
		fileByte []byte
		err      error
		// tempMember any
	)
	if len(models) == 0 {
		subjects = seederModelList
	} else {
		subjects = models
	}
	for _, model := range subjects {
		fileName, tempMember := model.Seed()
		fmt.Printf("%+v\n", reflect.TypeOf(tempMember)) //1
		if fileByte, err = os.ReadFile("db/seeds/" + fileName); err != nil {
			fmt.Println(err)
			return err
		}
		if err = json.Unmarshal(fileByte, &tempMember); err != nil {
			fmt.Println(err)
			return err
		}
		fmt.Printf("%+v\n", reflect.TypeOf(tempMember)) //2

	}
	return nil 
}

第一个打印语句返回[]models.AirportCodes,第二个打印语句返回[]interface{}。

这是我的接口和模型:

func (AirportCodes) Seed() (string, any) {
	return "airport_codes.json", []AirportCodes{}
}

type Seeder[T any] interface {
	Seed() (string, T)
	// Seed(*gorm.DB) error
	TableName() string
}

seederModelList = []globals.Seeder[any]{
		m.AirportCodes{},
		m.Term{},
	}
英文:

I'm trying to seed my Postgres database as functionally. In my case, SeedSchema() function can take any type struct. So I define a interface and create functions to my structs which will seed. I tried with generics and without.

When I unmarshall any json array from file as byte array, json.Unmarshall method change my tempMember member of struct. Exp, models.Term to map[string]interface{}. I've used unmarshall before this function and I've not seen like this situation.

Here is my SeedSchema() function:

func (db *Database) SeedSchema(models ...globals.Seeder[any]) error {
var (
	subjects []globals.Seeder[any]
	fileByte []byte
	err      error
	// tempMember any
)
if len(models) == 0 {
	subjects = seederModelList
} else {
	subjects = models
}
for _, model := range subjects {
	fileName, tempMember := model.Seed()
	fmt.Printf("%+v\n", reflect.TypeOf(tempMember)) //1
	if fileByte, err = os.ReadFile("db/seeds/" + fileName); err != nil {
		fmt.Println(err)
		return err
	}
	if err = json.Unmarshal(fileByte, &tempMember); err != nil {
		fmt.Println(err)
		return err
	}
	fmt.Printf("%+v\n", reflect.TypeOf(tempMember)) //2

}
return nil 
}

First print returns []models.AirportCodes and the second []interface {}.

Here is my interface and model:

func (AirportCodes) Seed() (string, any) {
	return "airport_codes.json", []AirportCodes{}
}

type Seeder[T any] interface {
	Seed() (string, T)
	// Seed(*gorm.DB) error
	TableName() string
}

seederModelList = []globals.Seeder[any]{
		m.AirportCodes{},
		m.Term{},
	}

答案1

得分: 1

几周后,我一直在寻找解决这个问题的方法,并查看了解组接口和示例。然后,就像icza所说的那样,我开始检查我的代码,了解类型之间的约定,并且我像这样解决了问题。如果你们有比我更好的答案,请添加回答。

数据:

[
    {
        "id":1,
        "name":"Term 1",
        "content": [
            "a1",
            "a2",
            "a3"
        ]
    }
]

结果:

[{ID:1 Name:Term 1 Content:[a1 a2 a3]}]

UnmarshalJSON 函数:

func (term *Term) UnmarshalJSON(data []byte) error {
	tempMap := map[string]interface{}{}
	if err := json.Unmarshal(data, &tempMap); err != nil {
		return err
	}
	*term = Term{
		Name: tempMap["name"].(string),
	}
	if tempMap["content"] != nil {
		for _, v := range tempMap["content"].([]interface{}) {
			(*term).Content = append((term).Content, v.(string))
		}
	}
	return nil
}

谢谢你的评论。

英文:

After a few weeks, I have looking for solve this problem and look unmarshaler interfaces and examples. Then Like what icza said, I started to look over the my code that convention between types and I solved like this. If you guys have better answer than mine, please add answer.

Data:

[
    {
        "id":1,
        "name":"Term 1",
        "content": [
            "a1",
            "a2",
            "a3"
        ]
    }
]

Result:

[{ID:1 Name:Term 1 Content:[a1 a2 a3]}]

UnmarshalJSON Function:

func (term *Term) UnmarshalJSON(data []byte) error {
	tempMap := map[string]interface{}{}
	if err := json.Unmarshal(data, &tempMap); err != nil {
		return err
	}
	*term = Term{
		Name: tempMap["name"].(string),
	}
	if tempMap["content"] != nil {
		for _, v := range tempMap["content"].([]interface{}) {
			(*term).Content = append((term).Content, v.(string))
		}
	}
	return nil
}

Thank you for comments.

huangapple
  • 本文由 发表于 2022年9月2日 16:27:58
  • 转载请务必保留本文链接:https://go.coder-hub.com/73579783.html
匿名

发表评论

匿名网友

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

确定