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

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

Why Json Unmarshall changing array type in Golang?

问题

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

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

这是我的SeedSchema()函数:

  1. func (db *Database) SeedSchema(models ...globals.Seeder[any]) error {
  2. var (
  3. subjects []globals.Seeder[any]
  4. fileByte []byte
  5. err error
  6. // tempMember any
  7. )
  8. if len(models) == 0 {
  9. subjects = seederModelList
  10. } else {
  11. subjects = models
  12. }
  13. for _, model := range subjects {
  14. fileName, tempMember := model.Seed()
  15. fmt.Printf("%+v\n", reflect.TypeOf(tempMember)) //1
  16. if fileByte, err = os.ReadFile("db/seeds/" + fileName); err != nil {
  17. fmt.Println(err)
  18. return err
  19. }
  20. if err = json.Unmarshal(fileByte, &tempMember); err != nil {
  21. fmt.Println(err)
  22. return err
  23. }
  24. fmt.Printf("%+v\n", reflect.TypeOf(tempMember)) //2
  25. }
  26. return nil
  27. }

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

这是我的接口和模型:

  1. func (AirportCodes) Seed() (string, any) {
  2. return "airport_codes.json", []AirportCodes{}
  3. }
  4. type Seeder[T any] interface {
  5. Seed() (string, T)
  6. // Seed(*gorm.DB) error
  7. TableName() string
  8. }
  9. seederModelList = []globals.Seeder[any]{
  10. m.AirportCodes{},
  11. m.Term{},
  12. }
英文:

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:

  1. func (db *Database) SeedSchema(models ...globals.Seeder[any]) error {
  2. var (
  3. subjects []globals.Seeder[any]
  4. fileByte []byte
  5. err error
  6. // tempMember any
  7. )
  8. if len(models) == 0 {
  9. subjects = seederModelList
  10. } else {
  11. subjects = models
  12. }
  13. for _, model := range subjects {
  14. fileName, tempMember := model.Seed()
  15. fmt.Printf("%+v\n", reflect.TypeOf(tempMember)) //1
  16. if fileByte, err = os.ReadFile("db/seeds/" + fileName); err != nil {
  17. fmt.Println(err)
  18. return err
  19. }
  20. if err = json.Unmarshal(fileByte, &tempMember); err != nil {
  21. fmt.Println(err)
  22. return err
  23. }
  24. fmt.Printf("%+v\n", reflect.TypeOf(tempMember)) //2
  25. }
  26. return nil
  27. }

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

Here is my interface and model:

  1. func (AirportCodes) Seed() (string, any) {
  2. return "airport_codes.json", []AirportCodes{}
  3. }
  4. type Seeder[T any] interface {
  5. Seed() (string, T)
  6. // Seed(*gorm.DB) error
  7. TableName() string
  8. }
  9. seederModelList = []globals.Seeder[any]{
  10. m.AirportCodes{},
  11. m.Term{},
  12. }

答案1

得分: 1

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

数据:

  1. [
  2. {
  3. "id":1,
  4. "name":"Term 1",
  5. "content": [
  6. "a1",
  7. "a2",
  8. "a3"
  9. ]
  10. }
  11. ]

结果:

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

UnmarshalJSON 函数:

  1. func (term *Term) UnmarshalJSON(data []byte) error {
  2. tempMap := map[string]interface{}{}
  3. if err := json.Unmarshal(data, &tempMap); err != nil {
  4. return err
  5. }
  6. *term = Term{
  7. Name: tempMap["name"].(string),
  8. }
  9. if tempMap["content"] != nil {
  10. for _, v := range tempMap["content"].([]interface{}) {
  11. (*term).Content = append((term).Content, v.(string))
  12. }
  13. }
  14. return nil
  15. }

谢谢你的评论。

英文:

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:

  1. [
  2. {
  3. "id":1,
  4. "name":"Term 1",
  5. "content": [
  6. "a1",
  7. "a2",
  8. "a3"
  9. ]
  10. }
  11. ]

Result:

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

UnmarshalJSON Function:

  1. func (term *Term) UnmarshalJSON(data []byte) error {
  2. tempMap := map[string]interface{}{}
  3. if err := json.Unmarshal(data, &tempMap); err != nil {
  4. return err
  5. }
  6. *term = Term{
  7. Name: tempMap["name"].(string),
  8. }
  9. if tempMap["content"] != nil {
  10. for _, v := range tempMap["content"].([]interface{}) {
  11. (*term).Content = append((term).Content, v.(string))
  12. }
  13. }
  14. return nil
  15. }

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:

确定